diff options
author | David 'Digit' Turner <digit@google.com> | 2014-03-10 15:16:30 +0100 |
---|---|---|
committer | David 'Digit' Turner <digit@google.com> | 2014-03-11 10:24:51 +0100 |
commit | aac93f1585bc9bdf8a57b6ed3c47c24f56a3990a (patch) | |
tree | 27409568ac69f1efca05cbe75bc10883088db5c2 /emulator/opengl/shared | |
parent | fd8752eb6a438832e0ba9a19db896614403f8945 (diff) | |
download | sdk-aac93f1585bc9bdf8a57b6ed3c47c24f56a3990a.zip sdk-aac93f1585bc9bdf8a57b6ed3c47c24f56a3990a.tar.gz sdk-aac93f1585bc9bdf8a57b6ed3c47c24f56a3990a.tar.bz2 |
emulator/opengl: Remove android::Mutex.
This patch removes the dependency on android::Mutex from
<cutils/threads.h> by providing a custom implementation, which
is a simple wrapper around pthread_mutex_t / CriticalSection,
under shared/emugl/common/mutex.h
+ Provide unit tests.
Change-Id: I379ef0c480c478ab9ba5f2faaf8274267eff37ba
Diffstat (limited to 'emulator/opengl/shared')
6 files changed, 305 insertions, 27 deletions
diff --git a/emulator/opengl/shared/OpenglCodecCommon/GLSharedGroup.cpp b/emulator/opengl/shared/OpenglCodecCommon/GLSharedGroup.cpp index c7da37a..a054562 100644 --- a/emulator/opengl/shared/OpenglCodecCommon/GLSharedGroup.cpp +++ b/emulator/opengl/shared/OpenglCodecCommon/GLSharedGroup.cpp @@ -242,19 +242,19 @@ GLSharedGroup::~GLSharedGroup() BufferData * GLSharedGroup::getBufferData(GLuint bufferId) { - android::AutoMutex _lock(m_lock); + emugl::Mutex::AutoLock _lock(m_lock); return m_buffers.valueFor(bufferId); } void GLSharedGroup::addBufferData(GLuint bufferId, GLsizeiptr size, void * data) { - android::AutoMutex _lock(m_lock); + emugl::Mutex::AutoLock _lock(m_lock); m_buffers.add(bufferId, new BufferData(size, data)); } void GLSharedGroup::updateBufferData(GLuint bufferId, GLsizeiptr size, void * data) { - android::AutoMutex _lock(m_lock); + emugl::Mutex::AutoLock _lock(m_lock); ssize_t idx = m_buffers.indexOfKey(bufferId); if (idx >= 0) { delete m_buffers.valueAt(idx); @@ -266,7 +266,7 @@ void GLSharedGroup::updateBufferData(GLuint bufferId, GLsizeiptr size, void * da GLenum GLSharedGroup::subUpdateBufferData(GLuint bufferId, GLintptr offset, GLsizeiptr size, void * data) { - android::AutoMutex _lock(m_lock); + emugl::Mutex::AutoLock _lock(m_lock); BufferData * buf = m_buffers.valueFor(bufferId); if ((!buf) || (buf->m_size < offset+size) || (offset < 0) || (size<0)) return GL_INVALID_VALUE; @@ -277,7 +277,7 @@ GLenum GLSharedGroup::subUpdateBufferData(GLuint bufferId, GLintptr offset, GLsi void GLSharedGroup::deleteBufferData(GLuint bufferId) { - android::AutoMutex _lock(m_lock); + emugl::Mutex::AutoLock _lock(m_lock); ssize_t idx = m_buffers.indexOfKey(bufferId); if (idx >= 0) { delete m_buffers.valueAt(idx); @@ -287,7 +287,7 @@ void GLSharedGroup::deleteBufferData(GLuint bufferId) void GLSharedGroup::addProgramData(GLuint program) { - android::AutoMutex _lock(m_lock); + emugl::Mutex::AutoLock _lock(m_lock); ProgramData *pData = m_programs.valueFor(program); if (pData) { @@ -300,7 +300,7 @@ void GLSharedGroup::addProgramData(GLuint program) void GLSharedGroup::initProgramData(GLuint program, GLuint numIndexes) { - android::AutoMutex _lock(m_lock); + emugl::Mutex::AutoLock _lock(m_lock); ProgramData *pData = m_programs.valueFor(program); if (pData) { @@ -310,7 +310,7 @@ void GLSharedGroup::initProgramData(GLuint program, GLuint numIndexes) bool GLSharedGroup::isProgramInitialized(GLuint program) { - android::AutoMutex _lock(m_lock); + emugl::Mutex::AutoLock _lock(m_lock); ProgramData* pData = m_programs.valueFor(program); if (pData) { @@ -321,7 +321,7 @@ bool GLSharedGroup::isProgramInitialized(GLuint program) void GLSharedGroup::deleteProgramData(GLuint program) { - android::AutoMutex _lock(m_lock); + emugl::Mutex::AutoLock _lock(m_lock); ProgramData *pData = m_programs.valueFor(program); if (pData) delete pData; @@ -330,7 +330,7 @@ void GLSharedGroup::deleteProgramData(GLuint program) void GLSharedGroup::attachShader(GLuint program, GLuint shader) { - android::AutoMutex _lock(m_lock); + emugl::Mutex::AutoLock _lock(m_lock); ProgramData* programData = m_programs.valueFor(program); ssize_t idx = m_shaders.indexOfKey(shader); if (programData && idx >= 0) { @@ -342,7 +342,7 @@ void GLSharedGroup::attachShader(GLuint program, GLuint shader) void GLSharedGroup::detachShader(GLuint program, GLuint shader) { - android::AutoMutex _lock(m_lock); + emugl::Mutex::AutoLock _lock(m_lock); ProgramData* programData = m_programs.valueFor(program); ssize_t idx = m_shaders.indexOfKey(shader); if (programData && idx >= 0) { @@ -354,7 +354,7 @@ void GLSharedGroup::detachShader(GLuint program, GLuint shader) void GLSharedGroup::setProgramIndexInfo(GLuint program, GLuint index, GLint base, GLint size, GLenum type, const char* name) { - android::AutoMutex _lock(m_lock); + emugl::Mutex::AutoLock _lock(m_lock); ProgramData* pData = m_programs.valueFor(program); if (pData) { @@ -382,7 +382,7 @@ void GLSharedGroup::setProgramIndexInfo(GLuint program, GLuint index, GLint base GLenum GLSharedGroup::getProgramUniformType(GLuint program, GLint location) { - android::AutoMutex _lock(m_lock); + emugl::Mutex::AutoLock _lock(m_lock); ProgramData* pData = m_programs.valueFor(program); GLenum type=0; if (pData) @@ -394,21 +394,21 @@ GLenum GLSharedGroup::getProgramUniformType(GLuint program, GLint location) bool GLSharedGroup::isProgram(GLuint program) { - android::AutoMutex _lock(m_lock); + emugl::Mutex::AutoLock _lock(m_lock); ProgramData* pData = m_programs.valueFor(program); return (pData!=NULL); } void GLSharedGroup::setupLocationShiftWAR(GLuint program) { - android::AutoMutex _lock(m_lock); + emugl::Mutex::AutoLock _lock(m_lock); ProgramData* pData = m_programs.valueFor(program); if (pData) pData->setupLocationShiftWAR(); } GLint GLSharedGroup::locationWARHostToApp(GLuint program, GLint hostLoc, GLint arrIndex) { - android::AutoMutex _lock(m_lock); + emugl::Mutex::AutoLock _lock(m_lock); ProgramData* pData = m_programs.valueFor(program); if (pData) return pData->locationWARHostToApp(hostLoc, arrIndex); else return hostLoc; @@ -416,7 +416,7 @@ GLint GLSharedGroup::locationWARHostToApp(GLuint program, GLint hostLoc, GLint a GLint GLSharedGroup::locationWARAppToHost(GLuint program, GLint appLoc) { - android::AutoMutex _lock(m_lock); + emugl::Mutex::AutoLock _lock(m_lock); ProgramData* pData = m_programs.valueFor(program); if (pData) return pData->locationWARAppToHost(appLoc); else return appLoc; @@ -424,7 +424,7 @@ GLint GLSharedGroup::locationWARAppToHost(GLuint program, GLint appLoc) bool GLSharedGroup::needUniformLocationWAR(GLuint program) { - android::AutoMutex _lock(m_lock); + emugl::Mutex::AutoLock _lock(m_lock); ProgramData* pData = m_programs.valueFor(program); if (pData) return pData->needUniformLocationWAR(); return false; @@ -432,21 +432,21 @@ bool GLSharedGroup::needUniformLocationWAR(GLuint program) GLint GLSharedGroup::getNextSamplerUniform(GLuint program, GLint index, GLint* val, GLenum* target) const { - android::AutoMutex _lock(m_lock); + emugl::Mutex::AutoLock _lock(m_lock); ProgramData* pData = m_programs.valueFor(program); return pData ? pData->getNextSamplerUniform(index, val, target) : -1; } bool GLSharedGroup::setSamplerUniform(GLuint program, GLint appLoc, GLint val, GLenum* target) { - android::AutoMutex _lock(m_lock); + emugl::Mutex::AutoLock _lock(m_lock); ProgramData* pData = m_programs.valueFor(program); return pData ? pData->setSamplerUniform(appLoc, val, target) : false; } bool GLSharedGroup::addShaderData(GLuint shader) { - android::AutoMutex _lock(m_lock); + emugl::Mutex::AutoLock _lock(m_lock); ShaderData* data = new ShaderData; if (data) { if (m_shaders.add(shader, data) < 0) { @@ -460,13 +460,13 @@ bool GLSharedGroup::addShaderData(GLuint shader) ShaderData* GLSharedGroup::getShaderData(GLuint shader) { - android::AutoMutex _lock(m_lock); + emugl::Mutex::AutoLock _lock(m_lock); return m_shaders.valueFor(shader); } void GLSharedGroup::unrefShaderData(GLuint shader) { - android::AutoMutex _lock(m_lock); + emugl::Mutex::AutoLock _lock(m_lock); ssize_t idx = m_shaders.indexOfKey(shader); if (idx >= 0) { unrefShaderDataLocked(idx); diff --git a/emulator/opengl/shared/OpenglCodecCommon/GLSharedGroup.h b/emulator/opengl/shared/OpenglCodecCommon/GLSharedGroup.h index e7341dc..02278a2 100644 --- a/emulator/opengl/shared/OpenglCodecCommon/GLSharedGroup.h +++ b/emulator/opengl/shared/OpenglCodecCommon/GLSharedGroup.h @@ -33,8 +33,8 @@ #include <utils/KeyedVector.h> #include <utils/List.h> #include <utils/String8.h> -#include <utils/threads.h> #include "FixedBuffer.h" +#include "emugl/common/mutex.h" #include "emugl/common/smart_ptr.h" struct BufferData { @@ -102,7 +102,7 @@ private: android::DefaultKeyedVector<GLuint, BufferData*> m_buffers; android::DefaultKeyedVector<GLuint, ProgramData*> m_programs; android::DefaultKeyedVector<GLuint, ShaderData*> m_shaders; - mutable android::Mutex m_lock; + mutable emugl::Mutex m_lock; void refShaderDataLocked(ssize_t shaderIdx); void unrefShaderDataLocked(ssize_t shaderIdx); 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 |