diff options
Diffstat (limited to 'emulator/opengl/shared/emugl/common')
| -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 | 
