aboutsummaryrefslogtreecommitdiffstats
path: root/emulator/opengl/shared/emugl/common
diff options
context:
space:
mode:
Diffstat (limited to 'emulator/opengl/shared/emugl/common')
-rw-r--r--emulator/opengl/shared/emugl/common/Android.mk26
-rw-r--r--emulator/opengl/shared/emugl/common/shared_library.cpp105
-rw-r--r--emulator/opengl/shared/emugl/common/shared_library.h85
-rw-r--r--emulator/opengl/shared/emugl/common/shared_library_unittest.cpp141
-rw-r--r--emulator/opengl/shared/emugl/common/testing/test_shared_library.cpp22
-rw-r--r--emulator/opengl/shared/emugl/common/thread.h102
-rw-r--r--emulator/opengl/shared/emugl/common/thread_pthread.cpp114
-rw-r--r--emulator/opengl/shared/emugl/common/thread_unittest.cpp109
-rw-r--r--emulator/opengl/shared/emugl/common/thread_win32.cpp122
9 files changed, 824 insertions, 2 deletions
diff --git a/emulator/opengl/shared/emugl/common/Android.mk b/emulator/opengl/shared/emugl/common/Android.mk
index 58dd6da..fb9ab57 100644
--- a/emulator/opengl/shared/emugl/common/Android.mk
+++ b/emulator/opengl/shared/emugl/common/Android.mk
@@ -9,16 +9,26 @@ commonSources := \
id_to_object_map.cpp \
lazy_instance.cpp \
pod_vector.cpp \
+ shared_library.cpp \
smart_ptr.cpp \
sockets.cpp \
thread_store.cpp \
host_commonSources := $(commonSources)
+host_commonLdLibs := -lstdc++
+
+ifneq (windows,$(HOST_OS))
+ host_commonSources += thread_pthread.cpp
+ host_commonLdLibs += -ldl -lpthread
+else
+ host_commonSources += thread_win32.cpp
+endif
+
$(call emugl-begin-host-static-library,libemugl_common)
LOCAL_SRC_FILES := $(host_commonSources)
$(call emugl-export,C_INCLUDES,$(EMUGL_PATH)/shared)
-$(call emugl-export,LDLIBS,-lstdc++)
+$(call emugl-export,LDLIBS,$(host_commonLdLibs))
$(call emugl-end-module)
ifdef EMUGL_BUILD_64BITS
@@ -26,7 +36,7 @@ ifdef EMUGL_BUILD_64BITS
LOCAL_SRC_FILES := $(host_commonSources)
$(call emugl-export,CFLAGS,-m64 -fPIC)
$(call emugl-export,C_INCLUDES,$(EMUGL_PATH)/shared)
- $(call emugl-export,LDLIBS,-lstdc++)
+ $(call emugl-export,LDLIBS,$(host_commonLdLibs))
$(call emugl-end-module)
endif
@@ -38,8 +48,10 @@ host_commonSources := \
lazy_instance_unittest.cpp \
pod_vector_unittest.cpp \
mutex_unittest.cpp \
+ shared_library_unittest.cpp \
smart_ptr_unittest.cpp \
thread_store_unittest.cpp \
+ thread_unittest.cpp \
$(call emugl-begin-host-executable,emugl_common_host_unittests)
LOCAL_SRC_FILES := $(host_commonSources)
@@ -52,3 +64,13 @@ ifdef EMUGL_BUILD_64BITS
$(call emugl-import,lib64emugl_common lib64emugl_gtest)
$(call emugl-end-module)
endif
+
+$(call emugl-begin-host-shared-library,libemugl_test_shared_library)
+LOCAL_SRC_FILES := testing/test_shared_library.cpp
+$(call emugl-end-module)
+
+ifdef EMUGL_BUILD_64BITS
+ $(call emugl-begin-host64-shared-library,lib64emugl_test_shared_library)
+ LOCAL_SRC_FILES := testing/test_shared_library.cpp
+ $(call emugl-end-module)
+endif
diff --git a/emulator/opengl/shared/emugl/common/shared_library.cpp b/emulator/opengl/shared/emugl/common/shared_library.cpp
new file mode 100644
index 0000000..db1c75c
--- /dev/null
+++ b/emulator/opengl/shared/emugl/common/shared_library.cpp
@@ -0,0 +1,105 @@
+// Copyright (C) 2014 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "emugl/common/shared_library.h"
+
+#include <stddef.h>
+#include <string.h>
+#include <stdio.h>
+
+#ifndef _WIN32
+#include <dlfcn.h>
+#include <stdlib.h>
+#endif
+
+namespace emugl {
+
+#ifdef _WIN32
+
+// static
+SharedLibrary* SharedLibrary::open(const char* libraryName) {
+ HMODULE lib = LoadLibrary(libraryName);
+ return lib ? new SharedLibrary(lib) : NULL;
+}
+
+SharedLibrary::SharedLibrary(HandleType lib) : mLib(lib) {}
+
+SharedLibrary::~SharedLibrary() {
+ if (mLib) {
+ FreeLibrary(mLib);
+ }
+}
+
+SharedLibrary::FunctionPtr SharedLibrary::findSymbol(
+ const char* symbolName) {
+ if (!mLib || !symbolName) {
+ return NULL;
+ }
+ return reinterpret_cast<FunctionPtr>(
+ GetProcAddress(mLib, symbolName));
+}
+
+#else // !_WIN32
+
+// static
+SharedLibrary* SharedLibrary::open(const char* libraryName) {
+ const char* libPath = libraryName;
+ char* path = NULL;
+
+ const char* libBaseName = strrchr(libraryName, '/');
+ if (!libBaseName) {
+ libBaseName = libraryName;
+ }
+
+ if (!strchr(libBaseName, '.')) {
+ // There is no extension in this library name, so append one.
+#ifdef __APPLE__
+ static const char kDllExtension[] = ".dylib";
+#else
+ static const char kDllExtension[] = ".so";
+#endif
+ size_t pathLen = strlen(libraryName) + sizeof(kDllExtension);
+ path = static_cast<char*>(malloc(pathLen));
+ snprintf(path, pathLen, "%s%s", libraryName, kDllExtension);
+ libPath = path;
+ }
+
+ void* lib = dlopen(libPath, RTLD_NOW);
+
+ if (path) {
+ free(path);
+ }
+
+ return lib ? new SharedLibrary(lib) : NULL;
+}
+
+SharedLibrary::SharedLibrary(HandleType lib) : mLib(lib) {}
+
+SharedLibrary::~SharedLibrary() {
+ if (mLib) {
+ dlclose(mLib);
+ }
+}
+
+SharedLibrary::FunctionPtr SharedLibrary::findSymbol(
+ const char* symbolName) {
+ if (!mLib || !symbolName) {
+ return NULL;
+ }
+ return reinterpret_cast<FunctionPtr>(dlsym(mLib, symbolName));
+}
+
+#endif // !_WIN32
+
+} // namespace emugl
diff --git a/emulator/opengl/shared/emugl/common/shared_library.h b/emulator/opengl/shared/emugl/common/shared_library.h
new file mode 100644
index 0000000..38d25bd
--- /dev/null
+++ b/emulator/opengl/shared/emugl/common/shared_library.h
@@ -0,0 +1,85 @@
+// Copyright (C) 2014 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef EMUGL_COMMON_SHARED_LIBRARY_H
+#define EMUGL_COMMON_SHARED_LIBRARY_H
+
+#ifdef _WIN32
+#include <windows.h>
+#endif
+
+namespace emugl {
+
+// A class used to open a platform-specific shared library, and probe
+// it for symbols. Usage is the following:
+//
+// // Open the library.
+// SharedLibrary* library = SharedLibrary::open("libFoo");
+// if (!library) {
+// ... could not find / open library!
+// }
+//
+// //Probe for function symbol.
+// FunctionPtr my_func = library->findSymbol("my_func");
+//
+// // Closes library/
+// delete library;
+//
+class SharedLibrary {
+public:
+ // Open a given library. |libraryName| can be either a full library
+ // path, or a simple name without an extension. On success, returns
+ // a new SharedLibrary instance that must be deleted by the caller.
+ static SharedLibrary* open(const char* libraryName);
+
+ // Closes an existing SharedLibrary instance.
+ ~SharedLibrary();
+
+ // Generic function pointer type, for values returned by the
+ // findSymbol() method.
+ typedef void (*FunctionPtr)(void);
+
+ // Probe a given SharedLibrary instance to find a symbol named
+ // |symbolName| in it. Return its address as a FunctionPtr, or
+ // NULL if the symbol is not found.
+ FunctionPtr findSymbol(const char* symbolName);
+
+private:
+#ifdef _WIN32
+ typedef HMODULE HandleType;
+#else
+ typedef void* HandleType;
+#endif
+
+ // Constructor intentionally hidden.
+ SharedLibrary(HandleType);
+
+ HandleType mLib;
+};
+
+// Macro to compose emugl shared library name under various OS and bitness
+// eg.
+// on x86_64, EMUGL_LIBNAME("foo") --> "lib64foo"
+
+#if defined(__x86_64__)
+# define EMUGL_LIBNAME(name) "lib64" name
+#elif defined(__i386__)
+# define EMUGL_LIBNAME(name) "lib" name
+#else
+/* This header is included by target w/o using EMUGL_LIBNAME(). Don't #error, leave it undefined */
+#endif
+
+} // namespace emugl
+
+#endif // EMUGL_COMMON_SHARED_LIBRARY_H
diff --git a/emulator/opengl/shared/emugl/common/shared_library_unittest.cpp b/emulator/opengl/shared/emugl/common/shared_library_unittest.cpp
new file mode 100644
index 0000000..cec4c73
--- /dev/null
+++ b/emulator/opengl/shared/emugl/common/shared_library_unittest.cpp
@@ -0,0 +1,141 @@
+// Copyright (C) 2014 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "emugl/common/shared_library.h"
+
+#include <gtest/gtest.h>
+
+#include <string>
+
+#include <limits.h>
+#include <string.h>
+
+// Hack to get the current executable's full path.
+namespace testing {
+namespace internal {
+
+extern std::string g_executable_path;
+
+} // namespace internal
+} // namespace testing
+
+namespace emugl {
+
+namespace {
+
+// Return the name/path of the test shared library to load.
+// Note that this doesn't include a platform-specific extension.
+// This assumes that the test shared library is under the lib/ sub-directory
+// of the current executable's path!
+std::string GetTestLibraryName() {
+ static const char kSubDir[] = "lib/";
+#ifdef __x86_64__
+ static const char kLibraryPrefix[] = "lib64";
+#else
+ static const char kLibraryPrefix[] = "lib";
+#endif
+ static const char kTestLibrarySuffix[] = "emugl_test_shared_library";
+
+ const char* exec_path = testing::internal::g_executable_path.c_str();
+
+#ifdef _WIN32
+ const char* p = strrchr(exec_path, '/');
+ const char* p2 = strrchr(exec_path, '\\');
+ if (p2) {
+ if (!p || p2 > p) {
+ p = p2;
+ }
+ }
+#else
+ const char* p = strrchr(exec_path, '/');
+#endif
+
+ std::string path;
+
+ if (!p) {
+ path = "./";
+ } else {
+ path = std::string(exec_path, p - exec_path + 1U);
+ }
+ path += kSubDir;
+ path += kLibraryPrefix;
+ path += kTestLibrarySuffix;
+ printf("Library path: %s\n", path.c_str());
+ return path;
+}
+
+class SharedLibraryTest : public testing::Test {
+public:
+ SharedLibraryTest() {
+ // Locate the shared library
+ mLibraryPath = GetTestLibraryName();
+ }
+
+ ~SharedLibraryTest() {}
+
+ const char* library_path() const { return mLibraryPath.c_str(); }
+
+private:
+ std::string mLibraryPath;
+};
+
+class ScopedSharedLibrary {
+public:
+ explicit ScopedSharedLibrary(SharedLibrary* lib) : mLib(lib) {}
+ ~ScopedSharedLibrary() {
+ delete mLib;
+ }
+ SharedLibrary* get() const { return mLib; }
+
+ SharedLibrary* operator->() { return mLib; }
+
+private:
+ SharedLibrary* mLib;
+};
+
+} // namespace
+
+TEST_F(SharedLibraryTest, Open) {
+ ScopedSharedLibrary lib(SharedLibrary::open(library_path()));
+ EXPECT_TRUE(lib.get());
+}
+
+TEST_F(SharedLibraryTest, OpenWithExtension) {
+ std::string path = library_path();
+#ifdef _WIN32
+ path += ".dll";
+#elif defined(__APPLE__)
+ path += ".dylib";
+#else
+ path += ".so";
+#endif
+ ScopedSharedLibrary lib(SharedLibrary::open(path.c_str()));
+ EXPECT_TRUE(lib.get());
+}
+
+TEST_F(SharedLibraryTest, FindSymbol) {
+ ScopedSharedLibrary lib(SharedLibrary::open(library_path()));
+ EXPECT_TRUE(lib.get());
+
+ if (lib.get()) {
+ typedef int (*FooFunction)(void);
+
+ FooFunction foo_func = reinterpret_cast<FooFunction>(
+ lib->findSymbol("foo_function"));
+ EXPECT_TRUE(foo_func);
+ EXPECT_EQ(42, (*foo_func)());
+ }
+}
+
+} // namespace emugl
diff --git a/emulator/opengl/shared/emugl/common/testing/test_shared_library.cpp b/emulator/opengl/shared/emugl/common/testing/test_shared_library.cpp
new file mode 100644
index 0000000..598a963
--- /dev/null
+++ b/emulator/opengl/shared/emugl/common/testing/test_shared_library.cpp
@@ -0,0 +1,22 @@
+// Copyright (C) 2014 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+// This source file must be compiled into a simple shared library which
+// will be used by shared_library_unittest.cpp to verify that the
+// emugl::SharedLibrary class works properly.
+
+
+extern "C" int foo_function(void) {
+ return 42;
+}
diff --git a/emulator/opengl/shared/emugl/common/thread.h b/emulator/opengl/shared/emugl/common/thread.h
new file mode 100644
index 0000000..d0f7d20
--- /dev/null
+++ b/emulator/opengl/shared/emugl/common/thread.h
@@ -0,0 +1,102 @@
+// Copyright (C) 2014 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef EMUGL_COMMON_THREAD_H
+#define EMUGL_COMMON_THREAD_H
+
+#ifdef _WIN32
+#include <windows.h>
+#else
+#include <pthread.h>
+#endif
+
+#include <stdint.h>
+
+namespace emugl {
+
+// Wrapper class for platform-specific threads.
+// To create your own thread, define a sub-class of emugl::Thread
+// and override its main() method.
+//
+// For example:
+//
+// class MyThread : public emugl::Thread {
+// public:
+// MyThread() : Thread() {}
+//
+// virtual intptr_t main() {
+// ... main thread loop implementation
+// return 0;
+// }
+// };
+//
+// ...
+//
+// // Create new instance, but does not start it.
+// MyThread* thread = new MyThread();
+//
+// // Start the thread.
+// thread->start();
+//
+// // Wait for thread completion, and gets result into |exitStatus|.
+// int exitStatus;
+// thread->wait(&exitStatus);
+//
+class Thread {
+public:
+ // Public constructor.
+ Thread();
+
+ // Virtual destructor.
+ virtual ~Thread();
+
+ // Override this method in your own thread sub-classes. This will
+ // be called when start() is invoked on the Thread instance.
+ virtual intptr_t main() = 0;
+
+ // Start a thread instance. Return true on success, false otherwise
+ // (e.g. if the thread was already started or terminated).
+ bool start();
+
+ // Wait for thread termination and retrieve exist status into
+ // |*exitStatus|. Return true on success, false otherwise.
+ // NOTE: |exitStatus| can be NULL.
+ bool wait(intptr_t *exitStatus);
+
+ // Check whether a thread has terminated. On success, return true
+ // and sets |*exitStatus|. On failure, return false.
+ // NOTE: |exitStatus| can be NULL.
+ bool tryWait(intptr_t *exitStatus);
+
+private:
+#ifdef _WIN32
+ static DWORD WINAPI thread_main(void* arg);
+
+ HANDLE mThread;
+ DWORD mThreadId;
+ CRITICAL_SECTION mLock;
+#else // !WIN32
+ static void* thread_main(void* arg);
+
+ pthread_t mThread;
+ pthread_mutex_t mLock;
+#endif
+ intptr_t mExitStatus;
+ bool mIsRunning;
+};
+
+} // namespace emugl
+
+#endif // EMUGL_COMMON_THREAD_H
+
diff --git a/emulator/opengl/shared/emugl/common/thread_pthread.cpp b/emulator/opengl/shared/emugl/common/thread_pthread.cpp
new file mode 100644
index 0000000..5dbc3ab
--- /dev/null
+++ b/emulator/opengl/shared/emugl/common/thread_pthread.cpp
@@ -0,0 +1,114 @@
+// Copyright (C) 2014 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "emugl/common/thread.h"
+
+#include "emugl/common/thread_store.h"
+
+#include <stdio.h>
+
+namespace emugl {
+
+namespace {
+
+class ScopedLocker {
+public:
+ ScopedLocker(pthread_mutex_t* mutex) : mMutex(mutex) {
+ pthread_mutex_lock(mMutex);
+ }
+
+ ~ScopedLocker() {
+ pthread_mutex_unlock(mMutex);
+ }
+private:
+ pthread_mutex_t* mMutex;
+};
+
+} // namespace
+
+Thread::Thread() :
+ mThread((pthread_t)NULL),
+ mExitStatus(0),
+ mIsRunning(false) {
+ pthread_mutex_init(&mLock, NULL);
+}
+
+Thread::~Thread() {
+ pthread_mutex_destroy(&mLock);
+}
+
+bool Thread::start() {
+ bool ret = true;
+ pthread_mutex_lock(&mLock);
+ mIsRunning = true;
+ if (pthread_create(&mThread, NULL, thread_main, this)) {
+ ret = false;
+ mIsRunning = false;
+ }
+ pthread_mutex_unlock(&mLock);
+ return ret;
+}
+
+bool Thread::wait(intptr_t *exitStatus) {
+ {
+ ScopedLocker locker(&mLock);
+ if (!mIsRunning) {
+ // Thread already stopped.
+ if (exitStatus) {
+ *exitStatus = mExitStatus;
+ }
+ return true;
+ }
+ }
+
+ // NOTE: Do not hold the lock when waiting for the thread to ensure
+ // it can update mIsRunning and mExitStatus properly in thread_main
+ // without blocking.
+ void *retval;
+ if (pthread_join(mThread, &retval)) {
+ return false;
+ }
+ if (exitStatus) {
+ *exitStatus = (intptr_t)retval;
+ }
+ return true;
+}
+
+bool Thread::tryWait(intptr_t *exitStatus) {
+ ScopedLocker locker(&mLock);
+ if (!mIsRunning) {
+ return false;
+ }
+ if (exitStatus) {
+ *exitStatus = mExitStatus;
+ }
+ return true;
+}
+
+// static
+void* Thread::thread_main(void *arg) {
+ Thread* self = reinterpret_cast<Thread*>(arg);
+ intptr_t ret = self->main();
+
+ pthread_mutex_lock(&self->mLock);
+ self->mIsRunning = false;
+ self->mExitStatus = ret;
+ pthread_mutex_unlock(&self->mLock);
+
+ ::emugl::ThreadStore::OnThreadExit();
+
+ return (void*)ret;
+}
+
+} // namespace emugl
diff --git a/emulator/opengl/shared/emugl/common/thread_unittest.cpp b/emulator/opengl/shared/emugl/common/thread_unittest.cpp
new file mode 100644
index 0000000..db1931f
--- /dev/null
+++ b/emulator/opengl/shared/emugl/common/thread_unittest.cpp
@@ -0,0 +1,109 @@
+// Copyright (C) 2014 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "emugl/common/thread.h"
+
+#include "emugl/common/mutex.h"
+
+#include <gtest/gtest.h>
+
+namespace emugl {
+
+namespace {
+
+// A simple thread instance that does nothing at all and exits immediately.
+class EmptyThread : public ::emugl::Thread {
+public:
+ intptr_t main() { return 42; }
+};
+
+class CountingThread : public ::emugl::Thread {
+public:
+ class State {
+ public:
+ State() : mLock(), mCount(0) {}
+ ~State() {}
+
+ void increment() {
+ mLock.lock();
+ mCount++;
+ mLock.unlock();
+ }
+
+ int count() const {
+ int ret;
+ mLock.lock();
+ ret = mCount;
+ mLock.unlock();
+ return ret;
+ }
+
+ private:
+ mutable Mutex mLock;
+ int mCount;
+ };
+
+ CountingThread(State* state) : mState(state) {}
+
+ intptr_t main() {
+ mState->increment();
+ return 0;
+ }
+
+private:
+ State* mState;
+};
+
+} // namespace
+
+TEST(ThreadTest, SimpleThread) {
+ Thread* thread = new EmptyThread();
+ EXPECT_TRUE(thread);
+ EXPECT_TRUE(thread->start());
+ intptr_t status;
+ EXPECT_TRUE(thread->wait(&status));
+ EXPECT_EQ(42, status);
+}
+
+TEST(ThreadTest, MultipleThreads) {
+ CountingThread::State state;
+ const size_t kMaxThreads = 100;
+ Thread* threads[kMaxThreads];
+
+ // Create all threads.
+ for (size_t n = 0; n < kMaxThreads; ++n) {
+ threads[n] = new CountingThread(&state);
+ EXPECT_TRUE(threads[n]) << "thread " << n;
+ }
+
+ // Start them all.
+ for (size_t n = 0; n < kMaxThreads; ++n) {
+ EXPECT_TRUE(threads[n]->start()) << "thread " << n;
+ }
+
+ // Wait for them all.
+ for (size_t n = 0; n < kMaxThreads; ++n) {
+ EXPECT_TRUE(threads[n]->wait(NULL)) << "thread " << n;
+ }
+
+ // Check state.
+ EXPECT_EQ((int)kMaxThreads, state.count());
+
+ // Delete them all.
+ for (size_t n = 0; n < kMaxThreads; ++n) {
+ delete threads[n];
+ }
+}
+
+} // namespace emugl
diff --git a/emulator/opengl/shared/emugl/common/thread_win32.cpp b/emulator/opengl/shared/emugl/common/thread_win32.cpp
new file mode 100644
index 0000000..f348ca8
--- /dev/null
+++ b/emulator/opengl/shared/emugl/common/thread_win32.cpp
@@ -0,0 +1,122 @@
+// Copyright (C) 2014 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "emugl/common/thread.h"
+
+#include "emugl/common/thread_store.h"
+
+namespace emugl {
+
+namespace {
+
+class ScopedLocker {
+public:
+ ScopedLocker(CRITICAL_SECTION* section) : mSection(section) {
+ EnterCriticalSection(mSection);
+ }
+
+ ~ScopedLocker() {
+ LeaveCriticalSection(mSection);
+ }
+private:
+ CRITICAL_SECTION* mSection;
+};
+
+} // namespace
+
+Thread::Thread() :
+ mThread(INVALID_HANDLE_VALUE),
+ mThreadId(0),
+ mExitStatus(0),
+ mIsRunning(false) {
+ InitializeCriticalSection(&mLock);
+}
+
+Thread::~Thread() {
+ if(mThread != INVALID_HANDLE_VALUE) {
+ CloseHandle(mThread);
+ }
+ DeleteCriticalSection(&mLock);
+}
+
+bool Thread::start() {
+ ScopedLocker locker(&mLock);
+
+ bool ret = true;
+ mIsRunning = true;
+ mThread = CreateThread(NULL, 0, &Thread::thread_main, this, 0, &mThreadId);
+ if (!mThread) {
+ ret = false;
+ mIsRunning = false;
+ }
+ return ret;
+}
+
+bool Thread::wait(intptr_t* exitStatus) {
+ {
+ ScopedLocker locker(&mLock);
+ if (!mIsRunning) {
+ // Thread already stopped.
+ if (exitStatus) {
+ *exitStatus = mExitStatus;
+ }
+ return true;
+ }
+ }
+
+ // NOTE: Do not hold lock during wait to aloow thread_main to
+ // properly update mIsRunning and mExitStatus on thread exit.
+ if (WaitForSingleObject(mThread, INFINITE) == WAIT_FAILED) {
+ return false;
+ }
+
+ if (exitStatus) {
+ ScopedLocker locker(&mLock);
+ *exitStatus = mExitStatus;
+ }
+ return true;
+}
+
+bool Thread::tryWait(intptr_t* exitStatus) {
+ ScopedLocker locker(&mLock);
+
+ if (!mIsRunning ||
+ WaitForSingleObject(mThread, 0) != WAIT_OBJECT_0) {
+ return false;
+ }
+
+ if (exitStatus) {
+ *exitStatus = mExitStatus;
+ }
+ return true;
+}
+
+// static
+DWORD WINAPI Thread::thread_main(void *arg)
+{
+ Thread* self = reinterpret_cast<Thread*>(arg);
+ intptr_t ret = self->main();
+
+ EnterCriticalSection(&self->mLock);
+ self->mIsRunning = false;
+ self->mExitStatus = ret;
+ LeaveCriticalSection(&self->mLock);
+
+ // Ensure all thread-local values are released for this thread.
+ ::emugl::ThreadStore::OnThreadExit();
+
+ return static_cast<DWORD>(ret);
+}
+
+} // namespace emugl