diff options
Diffstat (limited to 'emulator/opengl/shared/emugl/common')
| -rw-r--r-- | emulator/opengl/shared/emugl/common/Android.mk | 26 | ||||
| -rw-r--r-- | emulator/opengl/shared/emugl/common/shared_library.cpp | 105 | ||||
| -rw-r--r-- | emulator/opengl/shared/emugl/common/shared_library.h | 85 | ||||
| -rw-r--r-- | emulator/opengl/shared/emugl/common/shared_library_unittest.cpp | 141 | ||||
| -rw-r--r-- | emulator/opengl/shared/emugl/common/testing/test_shared_library.cpp | 22 | ||||
| -rw-r--r-- | emulator/opengl/shared/emugl/common/thread.h | 102 | ||||
| -rw-r--r-- | emulator/opengl/shared/emugl/common/thread_pthread.cpp | 114 | ||||
| -rw-r--r-- | emulator/opengl/shared/emugl/common/thread_unittest.cpp | 109 | ||||
| -rw-r--r-- | emulator/opengl/shared/emugl/common/thread_win32.cpp | 122 |
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 |
