aboutsummaryrefslogtreecommitdiffstats
path: root/emulator/opengl/shared
diff options
context:
space:
mode:
authorDavid 'Digit' Turner <digit@google.com>2014-03-10 15:16:30 +0100
committerDavid 'Digit' Turner <digit@google.com>2014-03-11 10:24:51 +0100
commitaac93f1585bc9bdf8a57b6ed3c47c24f56a3990a (patch)
tree27409568ac69f1efca05cbe75bc10883088db5c2 /emulator/opengl/shared
parentfd8752eb6a438832e0ba9a19db896614403f8945 (diff)
downloadsdk-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')
-rw-r--r--emulator/opengl/shared/OpenglCodecCommon/GLSharedGroup.cpp46
-rw-r--r--emulator/opengl/shared/OpenglCodecCommon/GLSharedGroup.h4
-rw-r--r--emulator/opengl/shared/emugl/common/Android.mk4
-rw-r--r--emulator/opengl/shared/emugl/common/mutex.h92
-rw-r--r--emulator/opengl/shared/emugl/common/mutex_unittest.cpp108
-rw-r--r--emulator/opengl/shared/emugl/common/testing/test_thread.h78
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