diff options
author | David 'Digit' Turner <digit@google.com> | 2014-07-09 15:52:13 +0200 |
---|---|---|
committer | David 'Digit' Turner <digit@google.com> | 2014-07-09 18:16:17 +0200 |
commit | 40cc9f9d50e998b0ce965b261ecf4d206a58618e (patch) | |
tree | 66272ee1b92a2267cc832618b43a59d650099e54 /emulator | |
parent | 242a075e3256fc7f369f0e5f93fd2ae91c255774 (diff) | |
download | sdk-40cc9f9d50e998b0ce965b261ecf4d206a58618e.zip sdk-40cc9f9d50e998b0ce965b261ecf4d206a58618e.tar.gz sdk-40cc9f9d50e998b0ce965b261ecf4d206a58618e.tar.bz2 |
emulator/opengl: refactor Thread class.
+ Add unit test.
Change-Id: I26d84cf590f6bfff3304be3f42dc0196bcc7f6d2
Diffstat (limited to 'emulator')
15 files changed, 467 insertions, 279 deletions
diff --git a/emulator/opengl/host/libs/libOpenglRender/RenderServer.cpp b/emulator/opengl/host/libs/libOpenglRender/RenderServer.cpp index de28f8f..53c65ee 100644 --- a/emulator/opengl/host/libs/libOpenglRender/RenderServer.cpp +++ b/emulator/opengl/host/libs/libOpenglRender/RenderServer.cpp @@ -77,7 +77,7 @@ RenderServer *RenderServer::create(char* addr, size_t addrLen) return server; } -int RenderServer::Main() +intptr_t RenderServer::main() { RenderThreadsSet threads; @@ -146,8 +146,7 @@ int RenderServer::Main() for (RenderThreadsSet::iterator t = threads.begin(); t != threads.end(); t++) { - int exitStatus; - (*t)->wait(&exitStatus); + (*t)->wait(NULL); delete (*t); } threads.clear(); diff --git a/emulator/opengl/host/libs/libOpenglRender/RenderServer.h b/emulator/opengl/host/libs/libOpenglRender/RenderServer.h index ff63c94..8be8a17 100644 --- a/emulator/opengl/host/libs/libOpenglRender/RenderServer.h +++ b/emulator/opengl/host/libs/libOpenglRender/RenderServer.h @@ -18,15 +18,15 @@ #include "SocketStream.h" #include "emugl/common/mutex.h" -#include "osThread.h" +#include "emugl/common/thread.h" -class RenderServer : public osUtils::Thread +class RenderServer : public emugl::Thread { public: static RenderServer *create(char* addr, size_t addrLen); virtual ~RenderServer(); - virtual int Main(); + virtual intptr_t main(); bool isExiting() const { return m_exiting; } diff --git a/emulator/opengl/host/libs/libOpenglRender/RenderThread.cpp b/emulator/opengl/host/libs/libOpenglRender/RenderThread.cpp index 19d6c1f..3dcfdb5 100644 --- a/emulator/opengl/host/libs/libOpenglRender/RenderThread.cpp +++ b/emulator/opengl/host/libs/libOpenglRender/RenderThread.cpp @@ -26,7 +26,7 @@ #define STREAM_BUFFER_SIZE 4*1024*1024 RenderThread::RenderThread(IOStream *stream, emugl::Mutex *lock) : - osUtils::Thread(), + emugl::Thread(), m_lock(lock), m_stream(stream), m_finished(false) @@ -43,7 +43,7 @@ RenderThread *RenderThread::create(IOStream *p_stream, emugl::Mutex *lock) return new RenderThread(p_stream, lock); } -int RenderThread::Main() +intptr_t RenderThread::main() { RenderThreadInfo tInfo; diff --git a/emulator/opengl/host/libs/libOpenglRender/RenderThread.h b/emulator/opengl/host/libs/libOpenglRender/RenderThread.h index e94d782..c1f919a 100644 --- a/emulator/opengl/host/libs/libOpenglRender/RenderThread.h +++ b/emulator/opengl/host/libs/libOpenglRender/RenderThread.h @@ -21,9 +21,9 @@ #include "renderControl_dec.h" #include "emugl/common/mutex.h" -#include "osThread.h" +#include "emugl/common/thread.h" -class RenderThread : public osUtils::Thread +class RenderThread : public emugl::Thread { public: static RenderThread* create(IOStream* p_stream, emugl::Mutex* mutex); @@ -32,7 +32,7 @@ public: private: RenderThread(IOStream* p_stream, emugl::Mutex* mutex); - virtual int Main(); + virtual intptr_t main(); private: emugl::Mutex *m_lock; diff --git a/emulator/opengl/host/libs/libOpenglRender/render_api.cpp b/emulator/opengl/host/libs/libOpenglRender/render_api.cpp index 5c9ffb1..42df668 100644 --- a/emulator/opengl/host/libs/libOpenglRender/render_api.cpp +++ b/emulator/opengl/host/libs/libOpenglRender/render_api.cpp @@ -243,8 +243,7 @@ int stopOpenGLRenderer(void) else if (s_renderThread) { // wait for the thread to exit - int status; - ret = s_renderThread->wait(&status); + ret = s_renderThread->wait(NULL); delete s_renderThread; s_renderThread = NULL; diff --git a/emulator/opengl/host/renderer/main.cpp b/emulator/opengl/host/renderer/main.cpp index 2c3f8e2..470e692 100644 --- a/emulator/opengl/host/renderer/main.cpp +++ b/emulator/opengl/host/renderer/main.cpp @@ -141,7 +141,7 @@ int main(int argc, char *argv[]) // // run the server listener loop // - server->Main(); + server->main(); #else // // on windows we need to handle messages for the diff --git a/emulator/opengl/shared/OpenglOsUtils/Android.mk b/emulator/opengl/shared/OpenglOsUtils/Android.mk index 42b57dd..4b1b05e 100644 --- a/emulator/opengl/shared/OpenglOsUtils/Android.mk +++ b/emulator/opengl/shared/OpenglOsUtils/Android.mk @@ -15,12 +15,12 @@ host_common_INCLUDES := $(LOCAL_PATH) ifeq ($(HOST_OS),windows) host_common_SRC_FILES += \ osProcessWin.cpp \ - osThreadWin.cpp + host_common_LDLIBS += -lws2_32 -lpsapi else host_common_SRC_FILES += \ osProcessUnix.cpp \ - osThreadUnix.cpp + host_common_LDLIBS += -ldl endif diff --git a/emulator/opengl/shared/OpenglOsUtils/osThread.h b/emulator/opengl/shared/OpenglOsUtils/osThread.h deleted file mode 100644 index 970396d..0000000 --- a/emulator/opengl/shared/OpenglOsUtils/osThread.h +++ /dev/null @@ -1,60 +0,0 @@ -/* -* Copyright (C) 2011 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 _OSUTILS_THREAD_H -#define _OSUTILS_THREAD_H - -#ifdef _WIN32 -#include <windows.h> -#else // !WIN32 -#include <pthread.h> -#endif - -namespace osUtils { - -class Thread -{ -public: - Thread(); - virtual ~Thread(); - - virtual int Main() = 0; - - bool start(); - bool wait(int *exitStatus); - bool trywait(int *exitStatus); - -private: -#ifdef _WIN32 - static DWORD WINAPI thread_main(void *p_arg); -#else // !WIN32 - static void* thread_main(void *p_arg); -#endif - -private: -#ifdef _WIN32 - HANDLE m_thread; - DWORD m_threadId; -#else // !WIN32 - pthread_t m_thread; - int m_exitStatus; - pthread_mutex_t m_lock; -#endif - bool m_isRunning; -}; - -} // of namespace osUtils - -#endif diff --git a/emulator/opengl/shared/OpenglOsUtils/osThreadUnix.cpp b/emulator/opengl/shared/OpenglOsUtils/osThreadUnix.cpp deleted file mode 100644 index ef2bebc..0000000 --- a/emulator/opengl/shared/OpenglOsUtils/osThreadUnix.cpp +++ /dev/null @@ -1,98 +0,0 @@ -/* -* Copyright (C) 2011 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 "osThread.h" - -#include "emugl/common/thread_store.h" - -#include <stdint.h> - -namespace osUtils { - -Thread::Thread() : - m_thread((pthread_t)NULL), - m_exitStatus(0), - m_isRunning(false) -{ - pthread_mutex_init(&m_lock, NULL); -} - -Thread::~Thread() -{ - pthread_mutex_destroy(&m_lock); -} - -bool -Thread::start() -{ - pthread_mutex_lock(&m_lock); - m_isRunning = true; - int ret = pthread_create(&m_thread, NULL, Thread::thread_main, this); - if(ret) { - m_isRunning = false; - } - pthread_mutex_unlock(&m_lock); - return m_isRunning; -} - -bool -Thread::wait(int *exitStatus) -{ - if (!m_isRunning) { - return false; - } - - void *retval; - if (pthread_join(m_thread,&retval)) { - return false; - } - - if (exitStatus) { - *exitStatus = (int)(uintptr_t)retval; - } - return true; -} - -bool -Thread::trywait(int *exitStatus) -{ - bool ret = false; - - pthread_mutex_lock(&m_lock); - if (!m_isRunning) { - *exitStatus = m_exitStatus; - ret = true; - } - pthread_mutex_unlock(&m_lock); - return ret; -} - -void * -Thread::thread_main(void *p_arg) -{ - Thread *self = (Thread *)p_arg; - int ret = self->Main(); - - pthread_mutex_lock(&self->m_lock); - self->m_isRunning = false; - self->m_exitStatus = ret; - pthread_mutex_unlock(&self->m_lock); - - ::emugl::ThreadStore::OnThreadExit(); - return (void*)(uintptr_t)ret; -} - -} // of namespace osUtils - diff --git a/emulator/opengl/shared/OpenglOsUtils/osThreadWin.cpp b/emulator/opengl/shared/OpenglOsUtils/osThreadWin.cpp deleted file mode 100644 index 1a30b97..0000000 --- a/emulator/opengl/shared/OpenglOsUtils/osThreadWin.cpp +++ /dev/null @@ -1,104 +0,0 @@ -/* -* Copyright (C) 2011 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 "osThread.h" - -#include "emugl/common/thread_store.h" - -namespace osUtils { - -Thread::Thread() : - m_thread(NULL), - m_threadId(0), - m_isRunning(false) -{ -} - -Thread::~Thread() -{ - if(m_thread) { - CloseHandle(m_thread); - } -} - -bool -Thread::start() -{ - m_isRunning = true; - m_thread = CreateThread(NULL, 0, &Thread::thread_main, this, 0, &m_threadId); - if(!m_thread) { - m_isRunning = false; - } - return m_isRunning; -} - -bool -Thread::wait(int *exitStatus) -{ - if (!m_isRunning) { - return false; - } - - if(WaitForSingleObject(m_thread, INFINITE) == WAIT_FAILED) { - return false; - } - - DWORD retval; - if (!GetExitCodeThread(m_thread,&retval)) { - return false; - } - - m_isRunning = 0; - - if (exitStatus) { - *exitStatus = retval; - } - return true; -} - -bool -Thread::trywait(int *exitStatus) -{ - if (!m_isRunning) { - return false; - } - - if(WaitForSingleObject(m_thread, 0) == WAIT_OBJECT_0) { - - DWORD retval; - if (!GetExitCodeThread(m_thread,&retval)) { - return true; - } - - if (exitStatus) { - *exitStatus = retval; - } - return true; - } - - return false; -} - -DWORD WINAPI -Thread::thread_main(void *p_arg) -{ - Thread *self = (Thread *)p_arg; - int ret = self->Main(); - self->m_isRunning = false; - ::emugl::ThreadStore::OnThreadExit(); - return ret; -} - -} // of namespace osUtils diff --git a/emulator/opengl/shared/emugl/common/Android.mk b/emulator/opengl/shared/emugl/common/Android.mk index e75f887..fb9ab57 100644 --- a/emulator/opengl/shared/emugl/common/Android.mk +++ b/emulator/opengl/shared/emugl/common/Android.mk @@ -17,8 +17,12 @@ commonSources := \ host_commonSources := $(commonSources) host_commonLdLibs := -lstdc++ + ifneq (windows,$(HOST_OS)) - host_commonLdLibs += -ldl + host_commonSources += thread_pthread.cpp + host_commonLdLibs += -ldl -lpthread +else + host_commonSources += thread_win32.cpp endif $(call emugl-begin-host-static-library,libemugl_common) @@ -47,6 +51,7 @@ host_commonSources := \ 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) 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 |