diff options
Diffstat (limited to 'emulator/opengl/shared/emugl')
| -rw-r--r-- | emulator/opengl/shared/emugl/common/Android.mk | 4 | ||||
| -rw-r--r-- | emulator/opengl/shared/emugl/common/mutex.h | 92 | ||||
| -rw-r--r-- | emulator/opengl/shared/emugl/common/mutex_unittest.cpp | 108 | ||||
| -rw-r--r-- | emulator/opengl/shared/emugl/common/testing/test_thread.h | 78 |
4 files changed, 280 insertions, 2 deletions
diff --git a/emulator/opengl/shared/emugl/common/Android.mk b/emulator/opengl/shared/emugl/common/Android.mk index 5c444fd..ae1c213 100644 --- a/emulator/opengl/shared/emugl/common/Android.mk +++ b/emulator/opengl/shared/emugl/common/Android.mk @@ -19,11 +19,11 @@ LOCAL_SRC_FILES := $(host_commonSources) $(call emugl-export,CFLAGS,-m64) $(call emugl-end-module) - ### emugl_common_unittests ############################################## host_commonSources := \ - smart_ptr_unittest.cpp + mutex_unittest.cpp \ + smart_ptr_unittest.cpp \ $(call emugl-begin-host-executable,emugl_common_host_unittests) LOCAL_SRC_FILES := $(host_commonSources) diff --git a/emulator/opengl/shared/emugl/common/mutex.h b/emulator/opengl/shared/emugl/common/mutex.h new file mode 100644 index 0000000..c6cdcf2 --- /dev/null +++ b/emulator/opengl/shared/emugl/common/mutex.h @@ -0,0 +1,92 @@ +// 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_MUTEX_H +#define EMUGL_MUTEX_H + +#ifdef _WIN32 +# define WIN32_LEAN_AND_MEAN 1 +# include <windows.h> +#else +# include <pthread.h> +#endif + +namespace emugl { + +// Simple wrapper class for mutexes. +class Mutex { +public: + // Constructor. + Mutex() { +#ifdef _WIN32 + ::InitializeCriticalSection(&mLock); +#else + ::pthread_mutex_init(&mLock, NULL); +#endif + } + + // Destructor. + ~Mutex() { +#ifdef _WIN32 + ::DeleteCriticalSection(&mLock); +#else + ::pthread_mutex_destroy(&mLock); +#endif + } + + // Acquire the mutex. + void lock() { +#ifdef _WIN32 + ::EnterCriticalSection(&mLock); +#else + ::pthread_mutex_lock(&mLock); +#endif + } + + // Release the mutex. + void unlock() { +#ifdef _WIN32 + ::LeaveCriticalSection(&mLock); +#else + ::pthread_mutex_unlock(&mLock); +#endif + } + + // Helper class to lock / unlock a mutex automatically on scope + // entry and exit. + class AutoLock { + public: + AutoLock(Mutex& mutex) : mMutex(&mutex) { + mMutex->lock(); + } + + ~AutoLock() { + mMutex->unlock(); + } + private: + Mutex* mMutex; + }; + +private: +#ifdef _WIN32 + CRITICAL_SECTION mLock; +#else + pthread_mutex_t mLock; +#endif + +}; + +} // namespace emugl + +#endif // EMUGL_MUTEX_H diff --git a/emulator/opengl/shared/emugl/common/mutex_unittest.cpp b/emulator/opengl/shared/emugl/common/mutex_unittest.cpp new file mode 100644 index 0000000..e952d75 --- /dev/null +++ b/emulator/opengl/shared/emugl/common/mutex_unittest.cpp @@ -0,0 +1,108 @@ +// 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/mutex.h" + +#include "emugl/common/testing/test_thread.h" + +#include <gtest/gtest.h> + +namespace emugl { + +// Check that construction and destruction doesn't crash. +TEST(Mutex, ConstructionDestruction) { + Mutex lock; +} + +// Check that a simple lock + unlock works. +TEST(Mutex, LockUnlock) { + Mutex lock; + lock.lock(); + lock.unlock(); +} + +// Check that AutoLock compiles and doesn't crash. +TEST(Mutex, AutoLock) { + Mutex mutex; + Mutex::AutoLock lock(mutex); +} + +// Wrapper class for threads. Does not use emugl::Thread intentionally. +// Common data type used by the following tests below. +struct ThreadParams { + ThreadParams() : mutex(), counter(0) {} + + Mutex mutex; + int counter; +}; + +// This thread function uses Mutex::lock/unlock to synchronize a counter +// increment operation. +static void* threadFunction(void* param) { + ThreadParams* p = static_cast<ThreadParams*>(param); + + p->mutex.lock(); + p->counter++; + p->mutex.unlock(); + return NULL; +} + +TEST(Mutex, Synchronization) { + const size_t kNumThreads = 2000; + TestThread* threads[kNumThreads]; + ThreadParams p; + + // Create and launch all threads. + for (size_t n = 0; n < kNumThreads; ++n) { + threads[n] = new TestThread(threadFunction, &p); + } + + // Wait until their completion. + for (size_t n = 0; n < kNumThreads; ++n) { + threads[n]->join(); + delete threads[n]; + } + + EXPECT_EQ(static_cast<int>(kNumThreads), p.counter); +} + +// This thread function uses a Mutex::AutoLock to protect the counter. +static void* threadAutoLockFunction(void* param) { + ThreadParams* p = static_cast<ThreadParams*>(param); + + Mutex::AutoLock lock(p->mutex); + p->counter++; + return NULL; +} + +TEST(Mutex, AutoLockSynchronization) { + const size_t kNumThreads = 2000; + TestThread* threads[kNumThreads]; + ThreadParams p; + + // Create and launch all threads. + for (size_t n = 0; n < kNumThreads; ++n) { + threads[n] = new TestThread(threadAutoLockFunction, &p); + } + + // Wait until their completion. + for (size_t n = 0; n < kNumThreads; ++n) { + threads[n]->join(); + delete threads[n]; + } + + EXPECT_EQ(static_cast<int>(kNumThreads), p.counter); +} + +} // namespace emugl diff --git a/emulator/opengl/shared/emugl/common/testing/test_thread.h b/emulator/opengl/shared/emugl/common/testing/test_thread.h new file mode 100644 index 0000000..2d758b3 --- /dev/null +++ b/emulator/opengl/shared/emugl/common/testing/test_thread.h @@ -0,0 +1,78 @@ +// 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_TESTING_TEST_THREAD_H +#define EMUGL_COMMON_TESTING_TEST_THREAD_H + +#ifdef _WIN32 +# define WIN32_LEAN_AND_MEAN 1 +# include <windows.h> +#else +# include <pthread.h> +#endif + +namespace emugl { + +// Very basic platform thread wrapper that only uses a tiny stack. +// This shall only be used during unit testing, and allows test code +// to not depend on the implementation of emugl::Thread. +class TestThread { +public: + // Main thread function type. + typedef void* (ThreadFunction)(void* param); + + // Constructor actually launches a new platform thread. + TestThread(ThreadFunction* func, void* funcParam) { +#ifdef _WIN32 + mThread = CreateThread(NULL, + 16384, + (DWORD WINAPI (*)(void*))func, + funcParam, + NULL, + NULL); +#else + pthread_attr_t attr; + pthread_attr_init(&attr); + pthread_attr_setstacksize(&attr, 16384); + pthread_create(&mThread, &attr, func, funcParam); + pthread_attr_destroy(&attr); +#endif + } + + ~TestThread() { +#ifdef _WIN32 + CloseHandle(mThread); +#endif + } + + void join() { +#ifdef _WIN32 + WaitForSingleObject(mThread, INFINITE); +#else + void* ret = NULL; + pthread_join(mThread, &ret); +#endif + } + +private: +#ifdef _WIN32 + HANDLE mThread; +#else + pthread_t mThread; +#endif +}; + +} // namespace emugl + +#endif // EMUGL_COMMON_TESTING_TEST_THREAD_H |
