diff options
Diffstat (limited to 'distrib/android-emugl/shared/emugl/common/thread_win32.cpp')
-rw-r--r-- | distrib/android-emugl/shared/emugl/common/thread_win32.cpp | 122 |
1 files changed, 122 insertions, 0 deletions
diff --git a/distrib/android-emugl/shared/emugl/common/thread_win32.cpp b/distrib/android-emugl/shared/emugl/common/thread_win32.cpp new file mode 100644 index 000000000..f348ca8ec --- /dev/null +++ b/distrib/android-emugl/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 |