From ae2f181397c309d5f4a58eccc6be86ee5d74eae6 Mon Sep 17 00:00:00 2001 From: Danila Klimenko Date: Wed, 13 May 2015 15:00:26 +0200 Subject: [PATCH] Readers-writers lock: updated interface to match C++14 standard --- base_c/include/embb/base/c/base.h | 2 +- base_c/include/embb/base/c/internal/platform.h | 4 ++-- base_c/include/embb/base/c/rwlock.h | 193 ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- base_c/include/embb/base/c/shared_mutex.h | 196 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ base_c/src/rwlock.c | 148 ---------------------------------------------------------------------------------------------------------------------------------------------------- base_c/src/shared_mutex.c | 148 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ base_c/test/main.cc | 6 +++--- base_c/test/rwlock_test.cc | 110 -------------------------------------------------------------------------------------------------------------- base_c/test/rwlock_test.h | 63 --------------------------------------------------------------- base_c/test/shared_mutex_test.cc | 110 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ base_c/test/shared_mutex_test.h | 63 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ base_cpp/include/embb/base/base.h | 2 +- base_cpp/include/embb/base/internal/platform.h | 4 ++-- base_cpp/include/embb/base/internal/shared_mutex-inl.h | 116 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ base_cpp/include/embb/base/rwlock.h | 210 ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ base_cpp/include/embb/base/shared_mutex.h | 304 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ base_cpp/src/rwlock.cc | 101 ----------------------------------------------------------------------------------------------------- base_cpp/src/shared_mutex.cc | 73 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ base_cpp/test/main.cc | 6 +++--- base_cpp/test/rwlock_test.cc | 86 -------------------------------------------------------------------------------------- base_cpp/test/rwlock_test.h | 63 --------------------------------------------------------------- base_cpp/test/shared_mutex_test.cc | 158 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ base_cpp/test/shared_mutex_test.h | 63 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 23 files changed, 1243 insertions(+), 986 deletions(-) delete mode 100644 base_c/include/embb/base/c/rwlock.h create mode 100644 base_c/include/embb/base/c/shared_mutex.h delete mode 100644 base_c/src/rwlock.c create mode 100644 base_c/src/shared_mutex.c delete mode 100644 base_c/test/rwlock_test.cc delete mode 100644 base_c/test/rwlock_test.h create mode 100644 base_c/test/shared_mutex_test.cc create mode 100644 base_c/test/shared_mutex_test.h create mode 100644 base_cpp/include/embb/base/internal/shared_mutex-inl.h delete mode 100644 base_cpp/include/embb/base/rwlock.h create mode 100644 base_cpp/include/embb/base/shared_mutex.h delete mode 100644 base_cpp/src/rwlock.cc create mode 100644 base_cpp/src/shared_mutex.cc delete mode 100644 base_cpp/test/rwlock_test.cc delete mode 100644 base_cpp/test/rwlock_test.h create mode 100644 base_cpp/test/shared_mutex_test.cc create mode 100644 base_cpp/test/shared_mutex_test.h diff --git a/base_c/include/embb/base/c/base.h b/base_c/include/embb/base/c/base.h index d16e355..0f697de 100644 --- a/base_c/include/embb/base/c/base.h +++ b/base_c/include/embb/base/c/base.h @@ -55,6 +55,6 @@ #include #include #include -#include +#include #endif /* EMBB_BASE_C_BASE_H_ */ diff --git a/base_c/include/embb/base/c/internal/platform.h b/base_c/include/embb/base/c/internal/platform.h index 358b435..2da445b 100644 --- a/base_c/include/embb/base/c/internal/platform.h +++ b/base_c/include/embb/base/c/internal/platform.h @@ -66,7 +66,7 @@ typedef struct embb_thread_t { typedef DWORD embb_thread_id_t; typedef CRITICAL_SECTION embb_mutex_t; typedef CONDITION_VARIABLE embb_condition_t; -typedef SRWLOCK embb_rwlock_t; +typedef SRWLOCK embb_shared_mutex_t; #define EMBB_DURATION_MIN_NANOSECONDS 1000 @@ -91,7 +91,7 @@ typedef struct embb_thread_t { typedef pthread_t embb_thread_id_t; typedef pthread_mutex_t embb_mutex_t; typedef pthread_cond_t embb_condition_t; -typedef pthread_rwlock_t embb_rwlock_t; +typedef pthread_rwlock_t embb_shared_mutex_t; #define EMBB_DURATION_MIN_NANOSECONDS 1 diff --git a/base_c/include/embb/base/c/rwlock.h b/base_c/include/embb/base/c/rwlock.h deleted file mode 100644 index ef62d5b..0000000 --- a/base_c/include/embb/base/c/rwlock.h +++ /dev/null @@ -1,193 +0,0 @@ -/* - * Copyright (c) 2014-2015, Siemens AG. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef EMBB_BASE_C_RWLOCK_H_ -#define EMBB_BASE_C_RWLOCK_H_ - -/** - * \defgroup C_BASE_RWLOCK Readers-Writers Lock - * - * Shared-read/exclusive-write lock for thread synchronization - * - * Provides an abstraction from platform-specific readers-writers lock - * implementations. - * - * \ingroup C_BASE - * \{ - */ - -#ifdef __cplusplus -extern "C" { -#endif - -#include -#include - -#ifdef DOXYGEN -/** - * Opaque type representing an rwlock. - */ -typedef opaque_type embb_rwlock_t; -#endif // DOXYGEN - -/** - * Initializes an rwlock - * - * \post \c rwlock is initialized - * - * \param rwlock Pointer to rwlock - * \return EMBB_SUCCESS if rwlock could be initialized \n - * EMBB_ERROR otherwise - * - * \memory (Potentially) allocates dynamic memory - * - * \notthreadsafe - * - * \see embb_rwlock_destroy() - */ -int embb_rwlock_init(embb_rwlock_t* rwlock); - -/** - * Waits until the rwlock can be locked for reading and locks it. - * - * \pre \c rwlock is initialized and not locked by the current thread. - * \post If successful, \c rwlock is locked for reading. - * - * \param rwlock Pointer to rwlock - * \return EMBB_SUCCESS if rwlock could be locked for reading \n - * EMBB_ERROR otherwise - * - * \threadsafe - * - * \see embb_rwlock_try_lock_read(), embb_rwlock_unlock_read() - */ -int embb_rwlock_lock_read(embb_rwlock_t* rwlock); - -/** - * Waits until the rwlock can be locked for writing and locks it. - * - * \pre \c rwlock is initialized and not locked by the current thread. - * \post If successful, \c rwlock is locked for writing. - * - * \param rwlock Pointer to rwlock - * \return EMBB_SUCCESS if rwlock could be locked for writing \n - * EMBB_ERROR otherwise - * - * \threadsafe - * - * \see embb_rwlock_try_lock_write(), embb_rwlock_unlock_write() - */ -int embb_rwlock_lock_write(embb_rwlock_t* rwlock); - -/** - * Tries to lock the rwlock for reading and returns immediately. - * - * \pre \c rwlock is initialized - * \post If successful, \c rwlock is locked for reading - * - * \param rwlock Pointer to rwlock - * \return EMBB_SUCCESS if rwlock could be locked for reading \n - * EMBB_BUSY if rwlock could not be locked for reading \n - * EMBB_ERROR if an error occurred - * - * \threadsafe - * - * \see embb_rwlock_lock_read(), embb_rwlock_unlock_read() - */ -int embb_rwlock_try_lock_read(embb_rwlock_t* rwlock); - -/** - * Tries to lock the rwlock for writing and returns immediately. - * - * \pre \c rwlock is initialized - * \post If successful, \c rwlock is locked for writing - * - * \param rwlock Pointer to rwlock - * \return EMBB_SUCCESS if rwlock could be locked for writing \n - * EMBB_BUSY if rwlock could not be locked for writing \n - * EMBB_ERROR if an error occurred - * - * \threadsafe - * - * \see embb_rwlock_lock_write(), embb_rwlock_unlock_write() - */ -int embb_rwlock_try_lock_write(embb_rwlock_t* rwlock); - -/** - * Unlocks an rwlock locked for reading. - * - * \pre \c rwlock has been locked for reading by the current thread. - * \post If successful, \c rwlock is unlocked. - * - * \param rwlock Pointer to rwlock - * \return EMBB_SUCCESS if the operation was successful \n - * EMBB_ERROR otherwise - * - * \threadsafe - * - * \see embb_rwlock_lock_read(), embb_rwlock_try_lock_read() - */ -int embb_rwlock_unlock_read(embb_rwlock_t* rwlock); - -/** - * Unlocks an rwlock locked for writing. - * - * \pre \c rwlock has been locked for writing by the current thread. - * \post If successful, \c rwlock is unlocked. - * - * \param rwlock Pointer to rwlock - * \return EMBB_SUCCESS if the operation was successful \n - * EMBB_ERROR otherwise - * - * \threadsafe - * - * \see embb_rwlock_lock_write(), embb_rwlock_try_lock_write() - */ -int embb_rwlock_unlock_write(embb_rwlock_t* rwlock); - -/** - * Destroys an rwlock and frees its resources. - * - * \pre \c rwlock has been initialized - * \post \c rwlock is uninitialized - * - * \param rwlock Pointer to rwlock - * - * \notthreadsafe - * - * \see embb_rwlock_init() - */ -void embb_rwlock_destroy(embb_rwlock_t* rwlock); - -#ifdef __cplusplus -} // Close extern "C" -#endif - -/** - * \} - */ - -#endif // EMBB_BASE_C_RWLOCK_H_ diff --git a/base_c/include/embb/base/c/shared_mutex.h b/base_c/include/embb/base/c/shared_mutex.h new file mode 100644 index 0000000..5855dfc --- /dev/null +++ b/base_c/include/embb/base/c/shared_mutex.h @@ -0,0 +1,196 @@ +/* + * Copyright (c) 2014-2015, Siemens AG. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef EMBB_BASE_C_SHARED_MUTEX_H_ +#define EMBB_BASE_C_SHARED_MUTEX_H_ + +/** + * \defgroup C_BASE_SHARED_MUTEX Shared mutex + * + * Shared mutexes for thread synchronization + * + * Provides an abstraction from platform-specific shared mutex implementations. + * Shared mutexes provide two levels of access: exclusive access - only one + * thread can own the mutex; shared access - several threads can share ownership + * of the same mutex. Shared mutexes facilitate the "single writer, multiple + * readers" scenarios. + * + * \ingroup C_BASE + * \{ + */ + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include + +#ifdef DOXYGEN +/** + * Opaque type representing a shared mutex. + */ +typedef opaque_type embb_shared_mutex_t; +#endif // DOXYGEN + +/** + * Initializes a shared mutex + * + * \post \c shared_mutex is initialized + * + * \param shared_mutex Pointer to shared mutex + * \return EMBB_SUCCESS if shared mutex could be initialized \n + * EMBB_ERROR otherwise + * + * \memory (Potentially) allocates dynamic memory + * + * \notthreadsafe + * + * \see embb_shared_mutex_destroy() + */ +int embb_shared_mutex_init(embb_shared_mutex_t* shared_mutex); + +/** + * Waits until the shared mutex can be locked for writing and locks it. + * + * \pre \c shared_mutex is initialized and not locked by the current thread. + * \post If successful, \c shared_mutex is locked for writing. + * + * \param shared_mutex Pointer to shared mutex + * \return EMBB_SUCCESS if shared_mutex could be locked for writing \n + * EMBB_ERROR otherwise + * + * \threadsafe + * + * \see embb_shared_mutex_try_lock(), embb_shared_mutex_unlock() + */ +int embb_shared_mutex_lock(embb_shared_mutex_t* shared_mutex); + +/** + * Tries to lock the shared mutex for writing and returns immediately. + * + * \pre \c shared_mutex is initialized + * \post If successful, \c shared_mutex is locked for writing + * + * \param shared_mutex Pointer to shared mutex + * \return EMBB_SUCCESS if shared_mutex could be locked for writing \n + * EMBB_BUSY if shared_mutex could not be locked for writing \n + * EMBB_ERROR if an error occurred + * + * \threadsafe + * + * \see embb_shared_mutex_lock(), embb_shared_mutex_unlock() + */ +int embb_shared_mutex_try_lock(embb_shared_mutex_t* shared_mutex); + +/** + * Unlocks the shared mutex locked for writing. + * + * \pre \c shared_mutex has been locked for writing by the current thread. + * \post If successful, \c shared_mutex is unlocked. + * + * \param shared_mutex Pointer to shared mutex + * \return EMBB_SUCCESS if the operation was successful \n + * EMBB_ERROR otherwise + * + * \threadsafe + * + * \see embb_shared_mutex_lock(), embb_shared_mutex_try_lock() + */ +int embb_shared_mutex_unlock(embb_shared_mutex_t* shared_mutex); + +/** + * Waits until the shared mutex can be locked for reading and locks it. + * + * \pre \c shared_mutex is initialized and not locked by the current thread. + * \post If successful, \c shared_mutex is locked for reading. + * + * \param shared_mutex Pointer to shared mutex + * \return EMBB_SUCCESS if shared_mutex could be locked for reading \n + * EMBB_ERROR otherwise + * + * \threadsafe + * + * \see embb_shared_mutex_try_lock_shared(), embb_shared_mutex_unlock_shared() + */ +int embb_shared_mutex_lock_shared(embb_shared_mutex_t* shared_mutex); + +/** + * Tries to lock the shared mutex for reading and returns immediately. + * + * \pre \c shared_mutex is initialized + * \post If successful, \c shared_mutex is locked for reading + * + * \param shared_mutex Pointer to shared mutex + * \return EMBB_SUCCESS if shared_mutex could be locked for reading \n + * EMBB_BUSY if shared_mutex could not be locked for reading \n + * EMBB_ERROR if an error occurred + * + * \threadsafe + * + * \see embb_shared_mutex_lock_shared(), embb_shared_mutex_unlock_shared() + */ +int embb_shared_mutex_try_lock_shared(embb_shared_mutex_t* shared_mutex); + +/** + * Unlocks the shared mutex locked for reading. + * + * \pre \c shared_mutex has been locked for reading by the current thread. + * \post If successful, \c shared_mutex is unlocked. + * + * \param shared_mutex Pointer to shared mutex + * \return EMBB_SUCCESS if the operation was successful \n + * EMBB_ERROR otherwise + * + * \threadsafe + * + * \see embb_shared_mutex_lock_shared(), embb_shared_mutex_try_lock_shared() + */ +int embb_shared_mutex_unlock_shared(embb_shared_mutex_t* shared_mutex); + +/** + * Destroys the shared mutex and frees its resources. + * + * \pre \c shared_mutex has been initialized + * \post \c shared_mutex is uninitialized + * + * \param shared_mutex Pointer to shared mutex + * + * \notthreadsafe + * + * \see embb_shared_mutex_init() + */ +void embb_shared_mutex_destroy(embb_shared_mutex_t* shared_mutex); + +#ifdef __cplusplus +} // Close extern "C" +#endif + +/** + * \} + */ + +#endif // EMBB_BASE_C_SHARED_MUTEX_H_ diff --git a/base_c/src/rwlock.c b/base_c/src/rwlock.c deleted file mode 100644 index a9bbbf5..0000000 --- a/base_c/src/rwlock.c +++ /dev/null @@ -1,148 +0,0 @@ -/* - * Copyright (c) 2014-2015, Siemens AG. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ - -#include -#include - -#include - -#ifdef EMBB_PLATFORM_THREADING_WINTHREADS - -int embb_rwlock_init(embb_rwlock_t* rwlock) { - InitializeSRWLock(rwlock); - return EMBB_SUCCESS; -} - -int embb_rwlock_lock_read(embb_rwlock_t* rwlock) { - AcquireSRWLockShared(rwlock); - return EMBB_SUCCESS; -} - -int embb_rwlock_lock_write(embb_rwlock_t* rwlock) { - AcquireSRWLockExclusive(rwlock); - return EMBB_SUCCESS; -} - -int embb_rwlock_try_lock_read(embb_rwlock_t* rwlock) { - BOOLEAN success; - success = TryAcquireSRWLockShared(rwlock); - if (success == FALSE) return EMBB_ERROR; - return EMBB_SUCCESS; -} - -int embb_rwlock_try_lock_write(embb_rwlock_t* rwlock) { - BOOLEAN success; - success = TryAcquireSRWLockExclusive(rwlock); - if (success == FALSE) return EMBB_ERROR; - return EMBB_SUCCESS; -} - -int embb_rwlock_unlock_read(embb_rwlock_t* rwlock) { - ReleaseSRWLockShared(rwlock); - return EMBB_SUCCESS; -} - -int embb_rwlock_unlock_write(embb_rwlock_t* rwlock) { - ReleaseSRWLockExclusive(rwlock); - return EMBB_SUCCESS; -} - -void embb_rwlock_destroy(embb_rwlock_t* rwlock) { - // Quoting MSDN: "SRW locks do not need to be explicitly destroyed". - EMBB_UNUSED(rwlock); -} - -#endif /* EMBB_PLATFORM_THREADING_WINTHREADS */ - -#ifdef EMBB_PLATFORM_THREADING_POSIXTHREADS - -int embb_rwlock_init(embb_rwlock_t* rwlock) { - int result = pthread_rwlock_init(rwlock, NULL); - if (result != 0) { - return EMBB_ERROR; - } - return EMBB_SUCCESS; -} - -int embb_rwlock_lock_read(embb_rwlock_t* rwlock) { - int result = pthread_rwlock_rdlock(rwlock); - if (result != 0) { - return EMBB_ERROR; - } - return EMBB_SUCCESS; -} - -int embb_rwlock_lock_write(embb_rwlock_t* rwlock) { - int result = pthread_rwlock_wrlock(rwlock); - if (result != 0) { - return EMBB_ERROR; - } - return EMBB_SUCCESS; -} - -int embb_rwlock_try_lock_read(embb_rwlock_t* rwlock) { - int result = pthread_rwlock_tryrdlock(rwlock); - if (result == 0) { - return EMBB_SUCCESS; - } - if (result == EBUSY) { - return EMBB_BUSY; - } - return EMBB_ERROR; -} - -int embb_rwlock_try_lock_write(embb_rwlock_t* rwlock) { - int result = pthread_rwlock_trywrlock(rwlock); - if (result == 0) { - return EMBB_SUCCESS; - } - if (result == EBUSY) { - return EMBB_BUSY; - } - return EMBB_ERROR; -} - -int embb_rwlock_unlock_read(embb_rwlock_t* rwlock) { - int result = pthread_rwlock_unlock(rwlock); - if (result != 0) { - return EMBB_ERROR; - } - return EMBB_SUCCESS; -} - -int embb_rwlock_unlock_write(embb_rwlock_t* rwlock) { - int result = pthread_rwlock_unlock(rwlock); - if (result != 0) { - return EMBB_ERROR; - } - return EMBB_SUCCESS; -} - -void embb_rwlock_destroy(embb_rwlock_t* rwlock) { - pthread_rwlock_destroy(rwlock); -} - -#endif /* EMBB_PLATFORM_THREADING_POSIXTHREADS */ diff --git a/base_c/src/shared_mutex.c b/base_c/src/shared_mutex.c new file mode 100644 index 0000000..0709d26 --- /dev/null +++ b/base_c/src/shared_mutex.c @@ -0,0 +1,148 @@ +/* + * Copyright (c) 2014-2015, Siemens AG. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include + +#include + +#ifdef EMBB_PLATFORM_THREADING_WINTHREADS + +int embb_shared_mutex_init(embb_shared_mutex_t* shared_mutex) { + InitializeSRWLock(shared_mutex); + return EMBB_SUCCESS; +} + +int embb_shared_mutex_lock(embb_shared_mutex_t* shared_mutex) { + AcquireSRWLockExclusive(shared_mutex); + return EMBB_SUCCESS; +} + +int embb_shared_mutex_try_lock(embb_shared_mutex_t* shared_mutex) { + BOOLEAN success; + success = TryAcquireSRWLockExclusive(shared_mutex); + if (success == FALSE) return EMBB_ERROR; + return EMBB_SUCCESS; +} + +int embb_shared_mutex_unlock(embb_shared_mutex_t* shared_mutex) { + ReleaseSRWLockExclusive(shared_mutex); + return EMBB_SUCCESS; +} + +int embb_shared_mutex_lock_shared(embb_shared_mutex_t* shared_mutex) { + AcquireSRWLockShared(shared_mutex); + return EMBB_SUCCESS; +} + +int embb_shared_mutex_try_lock_shared(embb_shared_mutex_t* shared_mutex) { + BOOLEAN success; + success = TryAcquireSRWLockShared(shared_mutex); + if (success == FALSE) return EMBB_ERROR; + return EMBB_SUCCESS; +} + +int embb_shared_mutex_unlock_shared(embb_shared_mutex_t* shared_mutex) { + ReleaseSRWLockShared(shared_mutex); + return EMBB_SUCCESS; +} + +void embb_shared_mutex_destroy(embb_shared_mutex_t* shared_mutex) { + // Quoting MSDN: "SRW locks do not need to be explicitly destroyed". + EMBB_UNUSED(shared_mutex); +} + +#endif /* EMBB_PLATFORM_THREADING_WINTHREADS */ + +#ifdef EMBB_PLATFORM_THREADING_POSIXTHREADS + +int embb_shared_mutex_init(embb_shared_mutex_t* shared_mutex) { + int result = pthread_rwlock_init(shared_mutex, NULL); + if (result != 0) { + return EMBB_ERROR; + } + return EMBB_SUCCESS; +} + +int embb_shared_mutex_lock(embb_shared_mutex_t* shared_mutex) { + int result = pthread_rwlock_wrlock(shared_mutex); + if (result != 0) { + return EMBB_ERROR; + } + return EMBB_SUCCESS; +} + +int embb_shared_mutex_try_lock(embb_shared_mutex_t* shared_mutex) { + int result = pthread_rwlock_trywrlock(shared_mutex); + if (result == 0) { + return EMBB_SUCCESS; + } + if (result == EBUSY) { + return EMBB_BUSY; + } + return EMBB_ERROR; +} + +int embb_shared_mutex_unlock(embb_shared_mutex_t* shared_mutex) { + int result = pthread_rwlock_unlock(shared_mutex); + if (result != 0) { + return EMBB_ERROR; + } + return EMBB_SUCCESS; +} + +int embb_shared_mutex_lock_shared(embb_shared_mutex_t* shared_mutex) { + int result = pthread_rwlock_rdlock(shared_mutex); + if (result != 0) { + return EMBB_ERROR; + } + return EMBB_SUCCESS; +} + +int embb_shared_mutex_try_lock_shared(embb_shared_mutex_t* shared_mutex) { + int result = pthread_rwlock_tryrdlock(shared_mutex); + if (result == 0) { + return EMBB_SUCCESS; + } + if (result == EBUSY) { + return EMBB_BUSY; + } + return EMBB_ERROR; +} + +int embb_shared_mutex_unlock_shared(embb_shared_mutex_t* shared_mutex) { + int result = pthread_rwlock_unlock(shared_mutex); + if (result != 0) { + return EMBB_ERROR; + } + return EMBB_SUCCESS; +} + +void embb_shared_mutex_destroy(embb_shared_mutex_t* shared_mutex) { + pthread_rwlock_destroy(shared_mutex); +} + +#endif /* EMBB_PLATFORM_THREADING_POSIXTHREADS */ diff --git a/base_c/test/main.cc b/base_c/test/main.cc index faa2430..e2ed1b6 100644 --- a/base_c/test/main.cc +++ b/base_c/test/main.cc @@ -35,7 +35,7 @@ #include #include #include -#include +#include #include #include #include @@ -52,7 +52,7 @@ using embb::base::test::CoreSetTest; using embb::base::test::ConditionVarTest; using embb::base::test::ThreadTest; using embb::base::test::ThreadSpecificStorageTest; -using embb::base::test::RWLockTest; +using embb::base::test::SharedMutexTest; PT_MAIN("Base C") { embb_log_set_log_level(EMBB_LOG_LEVEL_WARNING); @@ -70,7 +70,7 @@ PT_MAIN("Base C") { PT_RUN(ConditionVarTest); PT_RUN(ThreadTest); PT_RUN(ThreadSpecificStorageTest); - PT_RUN(RWLockTest); + PT_RUN(SharedMutexTest); PT_EXPECT(embb_get_bytes_allocated() == 0); } diff --git a/base_c/test/rwlock_test.cc b/base_c/test/rwlock_test.cc deleted file mode 100644 index 3950fde..0000000 --- a/base_c/test/rwlock_test.cc +++ /dev/null @@ -1,110 +0,0 @@ -/* - * Copyright (c) 2014-2015, Siemens AG. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ - -#include -#include - -namespace embb { -namespace base { -namespace test { - -RWLockTest::RWLockTest() - : counter_(0), - num_threads_(partest::TestSuite::GetDefaultNumThreads()), - num_iterations_(partest::TestSuite::GetDefaultNumIterations()) { - CreateUnit("Shared read") - .Pre(&RWLockTest::TestSharedRead_Pre, this) - .Add(&RWLockTest::TestSharedRead_ThreadMethod, this, - num_threads_, num_iterations_) - .Post(&RWLockTest::TestSharedRead_Post, this); - CreateUnit("Exclusive write") - .Pre(&RWLockTest::TestExclusiveWrite_Pre, this) - .Add(&RWLockTest::TestExclusiveWrite_ReaderMethod, this, - num_threads_, num_iterations_) - .Add(&RWLockTest::TestExclusiveWrite_WriterMethod, this, - num_threads_, num_iterations_) - .Post(&RWLockTest::TestExclusiveWrite_Post, this); -} - -void RWLockTest::TestSharedRead_Pre() { - int success = embb_rwlock_init(&rwlock_); - PT_ASSERT_EQ_MSG(success, EMBB_SUCCESS, "Failed to initialize rwlock."); -} - -void RWLockTest::TestSharedRead_ThreadMethod() { - int success = embb_rwlock_try_lock_read(&rwlock_); - PT_ASSERT_EQ_MSG(success, EMBB_SUCCESS, "Failed to lock for reading."); - - int spin = 10000; - while (--spin != 0); - - success = embb_rwlock_unlock_read(&rwlock_); - PT_ASSERT_EQ_MSG(success, EMBB_SUCCESS, "Failed to unlock (reading)."); -} - -void RWLockTest::TestSharedRead_Post() { - embb_rwlock_destroy(&rwlock_); -} - -void RWLockTest::TestExclusiveWrite_Pre() { - int success = embb_rwlock_init(&rwlock_); - PT_ASSERT_EQ_MSG(success, EMBB_SUCCESS, "Failed to initialize rwlock."); - - counter_ = 0; -} - -void RWLockTest::TestExclusiveWrite_ReaderMethod() { - // Just add some contention - - int success = embb_rwlock_try_lock_read(&rwlock_); - if (success != EMBB_SUCCESS) return; - - int spin = 10000; - while (--spin != 0); - - success = embb_rwlock_unlock_read(&rwlock_); - PT_ASSERT_EQ_MSG(success, EMBB_SUCCESS, "Failed to unlock (reading)."); -} - -void RWLockTest::TestExclusiveWrite_WriterMethod() { - int success = embb_rwlock_lock_write(&rwlock_); - PT_ASSERT_EQ_MSG(success, EMBB_SUCCESS, "Failed to lock for writing."); - - ++counter_; - - success = embb_rwlock_unlock_write(&rwlock_); - PT_ASSERT_EQ_MSG(success, EMBB_SUCCESS, "Failed to unlock (writing)."); -} - -void RWLockTest::TestExclusiveWrite_Post() { - PT_ASSERT_EQ_MSG(counter_, num_iterations_ * num_threads_, - "Counter value is inconsistent."); - embb_rwlock_destroy(&rwlock_); -} - -} // namespace test -} // namespace base -} // namespace embb diff --git a/base_c/test/rwlock_test.h b/base_c/test/rwlock_test.h deleted file mode 100644 index 8d208cd..0000000 --- a/base_c/test/rwlock_test.h +++ /dev/null @@ -1,63 +0,0 @@ -/* - * Copyright (c) 2014-2015, Siemens AG. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef BASE_C_TEST_RWLOCK_TEST_H_ -#define BASE_C_TEST_RWLOCK_TEST_H_ - -#include -#include -#include - - -namespace embb { -namespace base { -namespace test { - -class RWLockTest : public partest::TestCase { - public: - RWLockTest(); - - private: - void TestSharedRead_Pre(); - void TestSharedRead_ThreadMethod(); - void TestSharedRead_Post(); - - void TestExclusiveWrite_Pre(); - void TestExclusiveWrite_ReaderMethod(); - void TestExclusiveWrite_WriterMethod(); - void TestExclusiveWrite_Post(); - - embb_rwlock_t rwlock_; - size_t counter_; - size_t num_threads_; - size_t num_iterations_; -}; - -} // namespace test -} // namespace base -} // namespace embb - -#endif // BASE_C_TEST_RWLOCK_TEST_H_ diff --git a/base_c/test/shared_mutex_test.cc b/base_c/test/shared_mutex_test.cc new file mode 100644 index 0000000..9ec1005 --- /dev/null +++ b/base_c/test/shared_mutex_test.cc @@ -0,0 +1,110 @@ +/* + * Copyright (c) 2014-2015, Siemens AG. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include + +namespace embb { +namespace base { +namespace test { + +SharedMutexTest::SharedMutexTest() + : counter_(0), + num_threads_(partest::TestSuite::GetDefaultNumThreads()), + num_iterations_(partest::TestSuite::GetDefaultNumIterations()) { + CreateUnit("Shared read") + .Pre(&SharedMutexTest::TestSharedRead_Pre, this) + .Add(&SharedMutexTest::TestSharedRead_ThreadMethod, this, + num_threads_, num_iterations_) + .Post(&SharedMutexTest::TestSharedRead_Post, this); + CreateUnit("Exclusive write") + .Pre(&SharedMutexTest::TestExclusiveWrite_Pre, this) + .Add(&SharedMutexTest::TestExclusiveWrite_ReaderMethod, this, + num_threads_ / 2, num_iterations_) + .Add(&SharedMutexTest::TestExclusiveWrite_WriterMethod, this, + num_threads_ / 2, num_iterations_) + .Post(&SharedMutexTest::TestExclusiveWrite_Post, this); +} + +void SharedMutexTest::TestSharedRead_Pre() { + int success = embb_shared_mutex_init(&shared_mutex_); + PT_ASSERT_EQ_MSG(success, EMBB_SUCCESS, "Failed to initialize shared mutex."); +} + +void SharedMutexTest::TestSharedRead_ThreadMethod() { + int success = embb_shared_mutex_try_lock_shared(&shared_mutex_); + PT_ASSERT_EQ_MSG(success, EMBB_SUCCESS, "Failed to lock for reading."); + + int spin = 10000; + while (--spin != 0); + + success = embb_shared_mutex_unlock_shared(&shared_mutex_); + PT_ASSERT_EQ_MSG(success, EMBB_SUCCESS, "Failed to unlock (reading)."); +} + +void SharedMutexTest::TestSharedRead_Post() { + embb_shared_mutex_destroy(&shared_mutex_); +} + +void SharedMutexTest::TestExclusiveWrite_Pre() { + int success = embb_shared_mutex_init(&shared_mutex_); + PT_ASSERT_EQ_MSG(success, EMBB_SUCCESS, "Failed to initialize shared mutex."); + + counter_ = 0; +} + +void SharedMutexTest::TestExclusiveWrite_ReaderMethod() { + // Just add some contention + + int success = embb_shared_mutex_try_lock_shared(&shared_mutex_); + if (success != EMBB_SUCCESS) return; + + int spin = 10000; + while (--spin != 0); + + success = embb_shared_mutex_unlock_shared(&shared_mutex_); + PT_ASSERT_EQ_MSG(success, EMBB_SUCCESS, "Failed to unlock (reading)."); +} + +void SharedMutexTest::TestExclusiveWrite_WriterMethod() { + int success = embb_shared_mutex_lock(&shared_mutex_); + PT_ASSERT_EQ_MSG(success, EMBB_SUCCESS, "Failed to lock for writing."); + + ++counter_; + + success = embb_shared_mutex_unlock(&shared_mutex_); + PT_ASSERT_EQ_MSG(success, EMBB_SUCCESS, "Failed to unlock (writing)."); +} + +void SharedMutexTest::TestExclusiveWrite_Post() { + PT_ASSERT_EQ_MSG(counter_, num_iterations_ * (num_threads_ / 2), + "Counter value is inconsistent."); + embb_shared_mutex_destroy(&shared_mutex_); +} + +} // namespace test +} // namespace base +} // namespace embb diff --git a/base_c/test/shared_mutex_test.h b/base_c/test/shared_mutex_test.h new file mode 100644 index 0000000..67f4a31 --- /dev/null +++ b/base_c/test/shared_mutex_test.h @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2014-2015, Siemens AG. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef BASE_C_TEST_SHARED_MUTEX_TEST_H_ +#define BASE_C_TEST_SHARED_MUTEX_TEST_H_ + +#include +#include +#include + + +namespace embb { +namespace base { +namespace test { + +class SharedMutexTest : public partest::TestCase { + public: + SharedMutexTest(); + + private: + void TestSharedRead_Pre(); + void TestSharedRead_ThreadMethod(); + void TestSharedRead_Post(); + + void TestExclusiveWrite_Pre(); + void TestExclusiveWrite_ReaderMethod(); + void TestExclusiveWrite_WriterMethod(); + void TestExclusiveWrite_Post(); + + embb_shared_mutex_t shared_mutex_; + size_t counter_; + size_t num_threads_; + size_t num_iterations_; +}; + +} // namespace test +} // namespace base +} // namespace embb + +#endif // BASE_C_TEST_SHARED_MUTEX_TEST_H_ diff --git a/base_cpp/include/embb/base/base.h b/base_cpp/include/embb/base/base.h index 26d0730..3478685 100644 --- a/base_cpp/include/embb/base/base.h +++ b/base_cpp/include/embb/base/base.h @@ -59,6 +59,6 @@ #include #include #include -#include +#include #endif // EMBB_BASE_BASE_H_ diff --git a/base_cpp/include/embb/base/internal/platform.h b/base_cpp/include/embb/base/internal/platform.h index 04a2b34..9106764 100644 --- a/base_cpp/include/embb/base/internal/platform.h +++ b/base_cpp/include/embb/base/internal/platform.h @@ -44,7 +44,7 @@ typedef embb_thread_t ThreadType; typedef DWORD IDType; typedef embb_mutex_t MutexType; typedef embb_condition_t ConditionVariableType; -typedef embb_rwlock_t RWLockType; +typedef embb_shared_mutex_t SharedMutexType; } // namespace internal } // namespace base @@ -60,7 +60,7 @@ typedef embb_thread_t ThreadType; typedef embb_thread_id_t IDType; typedef embb_mutex_t MutexType; typedef embb_condition_t ConditionVariableType; -typedef embb_rwlock_t RWLockType; +typedef embb_shared_mutex_t SharedMutexType; } // namespace internal } // namespace base diff --git a/base_cpp/include/embb/base/internal/shared_mutex-inl.h b/base_cpp/include/embb/base/internal/shared_mutex-inl.h new file mode 100644 index 0000000..5a3ea0b --- /dev/null +++ b/base_cpp/include/embb/base/internal/shared_mutex-inl.h @@ -0,0 +1,116 @@ +/* + * Copyright (c) 2014-2015, Siemens AG. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef EMBB_BASE_INTERNAL_SHARED_MUTEX_INL_H_ +#define EMBB_BASE_INTERNAL_SHARED_MUTEX_INL_H_ + +#include +#include // For std::swap() + +namespace embb { +namespace base { + +template +SharedLock::SharedLock() + : shared_mutex_(NULL), locked_(false) {} + +template +SharedLock::SharedLock(SharedMutex& shared_mutex) + : shared_mutex_(&shared_mutex), locked_(false) { + shared_mutex_->LockShared(); + locked_ = true; +} + +template +SharedLock::SharedLock(SharedMutex& shared_mutex, DeferLockTag) + : shared_mutex_(&shared_mutex), locked_(false) {} + +template +SharedLock::SharedLock(SharedMutex& shared_mutex, TryLockTag) + : shared_mutex_(&shared_mutex), locked_(shared_mutex_->TryLockShared()) {} + +template +SharedLock::SharedLock(SharedMutex& shared_mutex, AdoptLockTag) + : shared_mutex_(&shared_mutex), locked_(true) {} + +template +SharedLock::~SharedLock() { + if (OwnsLock()) { + shared_mutex_->UnlockShared(); + } +} + +template +void SharedLock::LockShared() { + if (shared_mutex_ == NULL || locked_) { + EMBB_THROW(ErrorException, "Mutex not set or locked"); + } + shared_mutex_->LockShared(); + locked_ = true; +} + +template +bool SharedLock::TryLockShared() { + if (shared_mutex_ == NULL || locked_) { + EMBB_THROW(ErrorException, "Mutex not set or locked"); + } + locked_ = shared_mutex_->TryLockShared(); + return locked_; +} + +template +void SharedLock::UnlockShared() { + if (shared_mutex_ == NULL || !locked_) { + EMBB_THROW(ErrorException, "Mutex not set or unlocked"); + } + shared_mutex_->UnlockShared(); + locked_ = false; +} + +template +void SharedLock::Swap(SharedLock& other) { + std::swap(shared_mutex_, other.shared_mutex_); + std::swap(locked_, other.locked_); +} + +template +SharedMutex* SharedLock::Release() { + SharedMutex* to_release = shared_mutex_; + shared_mutex_ = NULL; + locked_ = false; + return to_release; +} + +template +bool SharedLock::OwnsLock() const { + assert(!(locked_ && (shared_mutex_ == NULL))); + return locked_; +} + +} // namespace base +} // namespace embb + +#endif // EMBB_BASE_INTERNAL_SHARED_MUTEX_INL_H_ diff --git a/base_cpp/include/embb/base/rwlock.h b/base_cpp/include/embb/base/rwlock.h deleted file mode 100644 index 64ecd2a..0000000 --- a/base_cpp/include/embb/base/rwlock.h +++ /dev/null @@ -1,210 +0,0 @@ -/* - * Copyright (c) 2014-2015, Siemens AG. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef EMBB_BASE_RWLOCK_H_ -#define EMBB_BASE_RWLOCK_H_ - -#include -#include - -namespace embb { -namespace base { - -/** - * \defgroup CPP_BASE_RWLOCK Readers-Writers Lock - * - * Shared-read/exclusive-write lock for thread synchronization. - * - * \ingroup CPP_BASE - */ - -/** - * Shared-read/exclusive-write (readers-writers) lock. - * - * Allows simultaneous shared access for concurrent readers, but only exclusive - * access for writers. Cannot be locked recursively. Fairness and/or FIFO order - * guaranties are platform specific and should be assumed non-existent. - * - * \ingroup CPP_BASE_RWLOCK - */ -class RWLock { - public: - /** - * Creates an rwlock which is in unlocked state. - * - * \memory Potentially allocates dynamic memory - * \notthreadsafe - */ - RWLock(); - - /** - * Destroys internal representation. - */ - ~RWLock(); - - /** - * Waits until the rwlock can be locked for reading and locks it. - * - * \pre The \c rwlock is not locked by the current thread. - * \post The \c rwlock is locked for reading. - * - * \threadsafe - * - * \see TryLockRead(), UnlockRead() - */ - void LockRead(); - - /** - * Waits until the rwlock can be locked for writing and locks it. - * - * \pre \c rwlock is initialized and not locked by the current thread. - * \post \c rwlock is locked for writing. - * - * \threadsafe - * - * \see TryLockWrite(), UnlockWrite() - */ - void LockWrite(); - - /** - * Tries to lock the rwlock for reading and returns immediately. - * - * \pre \c rwlock is not locked by the current thread. - * \post If successful, \c rwlock is locked for reading. - * - * \return \c true if rwlock was locked for reading \n - * \c false otherwise - * - * \threadsafe - * - * \see LockRead(), UnlockRead() - */ - bool TryLockRead(); - - /** - * Tries to lock the rwlock for writing and returns immediately. - * - * \pre \c rwlock is not locked by the current thread. - * \post If successful, \c rwlock is locked for writing. - * - * \return \c true if rwlock was locked for reading \n - * \c false otherwise - * - * \threadsafe - * - * \see LockWrite(), UnlockWrite() - */ - bool TryLockWrite(); - - /** - * Unlocks an rwlock locked for reading. - * - * \pre \c rwlock has been locked for reading by the current thread. - * \post \c rwlock is unlocked. - * - * \threadsafe - * - * \see LockRead(), TryLockRead() - */ - void UnlockRead(); - - /** - * Unlocks an rwlock locked for writing. - * - * \pre \c rwlock has been locked for writing by the current thread. - * \post \c rwlock is unlocked. - * - * \threadsafe - * - * \see LockWrite(), TryLockWrite() - */ - void UnlockWrite(); - - - /** - * Adaptor class for the readers lock that can be used with "LockGuard" and/or - * "UniqueLock" ownership wrappers. - * - * \see LockGuard, UniqueLock - */ - class ReaderLock { - public: - ReaderLock(RWLock& rwlock); - void Lock(); - bool TryLock(); - void Unlock(); - private: - ReaderLock(const ReaderLock&); - ReaderLock& operator=(const ReaderLock&); - RWLock& rwlock_; - }; - - /** - * Adaptor class for the writers lock that can be used with "LockGuard" and/or - * "UniqueLock" ownership wrappers. - * - * \see LockGuard, UniqueLock - */ - class WriterLock { - public: - WriterLock(RWLock& rwlock); - void Lock(); - bool TryLock(); - void Unlock(); - private: - WriterLock(const WriterLock&); - WriterLock& operator=(const WriterLock&); - RWLock& rwlock_; - }; - - /** - * Returns an adaptor for the readers lock to be used with "LockGuard" and/or - * "UniqueLock" ownership wrappers. - */ - ReaderLock& GetReaderLock(); - - /** - * Returns an adaptor for the writes lock to be used with "LockGuard" and/or - * "UniqueLock" ownership wrappers. - */ - WriterLock& GetWriterLock(); - - private: - /** - * Disables copy construction and assignment. - */ - RWLock(const RWLock&); - RWLock& operator=(const RWLock&); - - internal::RWLockType rwlock_; /**< Actual rwlock implementation from base_c */ - ReaderLock reader_lock_; /**< Lock adaptor for readers */ - WriterLock writer_lock_; /**< Lock adaptor for writers */ -}; - -} // namespace base -} // namespace embb - -#endif // EMBB_BASE_RWLOCK_H_ diff --git a/base_cpp/include/embb/base/shared_mutex.h b/base_cpp/include/embb/base/shared_mutex.h new file mode 100644 index 0000000..4e2138d --- /dev/null +++ b/base_cpp/include/embb/base/shared_mutex.h @@ -0,0 +1,304 @@ +/* + * Copyright (c) 2014-2015, Siemens AG. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef EMBB_BASE_SHARED_MUTEX_H_ +#define EMBB_BASE_SHARED_MUTEX_H_ + +#include +#include +#include + +namespace embb { +namespace base { + +/** + * \defgroup CPP_BASE_SHARED_MUTEX Shared mutex + * + * Shared mutexes for thread synchronization + * + * Provides an abstraction from platform-specific shared mutex implementations. + * Shared mutexes provide two levels of access: exclusive access - only one + * thread can own the mutex; shared access - several threads can share ownership + * of the same mutex. Shared mutexes facilitate the "single writer, multiple + * readers" scenarios. + * + * \ingroup CPP_BASE + */ + +/** + * Shared mutex providing shared-read/exclusive-write access synchronization. + * + * Allows simultaneous shared access for concurrent readers, but only exclusive + * access for writers. Cannot be locked recursively. Fairness and/or FIFO order + * guarantees are platform specific and should be assumed non-existent. + * + * \see Mutex + * + * \ingroup CPP_BASE_SHARED_MUTEX + */ +class SharedMutex { + public: + /** + * Creates the shared mutex object which is initially in an unlocked state. + * + * \memory Potentially allocates dynamic memory + * + * \notthreadsafe + */ + SharedMutex(); + + /** + * Destroys internal representation. + */ + ~SharedMutex(); + + /** + * Waits until the shared mutex can be locked for writing and locks it. + * + * \pre \c shared_mutex is initialized and not locked by the current thread. + * \post \c shared_mutex is locked for writing. + * + * \threadsafe + * + * \see TryLock(), Unlock() + */ + void Lock(); + + /** + * Tries to lock the shared mutex for writing and returns immediately. + * + * \pre \c shared_mutex is not locked by the current thread. + * \post If successful, \c shared_mutex is locked for writing. + * + * \return \c true if shared mutex was locked for reading \n + * \c false otherwise + * + * \threadsafe + * + * \see Lock(), Unlock() + */ + bool TryLock(); + + /** + * Unlocks the shared mutex locked for writing. + * + * \pre \c shared_mutex has been locked for writing by the current thread. + * \post \c shared_mutex is unlocked. + * + * \threadsafe + * + * \see Lock(), TryLock() + */ + void Unlock(); + + /** + * Waits until the shared mutex can be locked for reading and locks it. + * + * \pre The \c shared_mutex is not locked by the current thread. + * \post The \c shared_mutex is locked for reading. + * + * \threadsafe + * + * \see TryLockShared(), UnlockShared() + */ + void LockShared(); + + /** + * Tries to lock the shared mutex for reading and returns immediately. + * + * \pre \c shared_mutex is not locked by the current thread. + * \post If successful, \c shared_mutex is locked for reading. + * + * \return \c true if shared mutex was locked for reading \n + * \c false otherwise + * + * \threadsafe + * + * \see LockShared(), UnlockShared() + */ + bool TryLockShared(); + + /** + * Unlocks the shared mutex locked for reading. + * + * \pre \c shared_mutex has been locked for reading by the current thread. + * \post \c shared_mutex is unlocked. + * + * \threadsafe + * + * \see LockShared(), TryLockShared() + */ + void UnlockShared(); + + private: + /** + * Disables copy construction and assignment. + */ + SharedMutex(const SharedMutex&); + SharedMutex& operator=(const SharedMutex&); + + /** Actual shared mutex implementation from base_c */ + internal::SharedMutexType shared_mutex_; +}; + +/** + * Ownership wrapper for a shared mutex that works on the shared access level + * (i.e. it locks a shared mutex in shared "readers" mode). + * + * For exclusive ownership wrapping, use UniqueLock. + * + * \notthreadsafe + * + * \tparam SharedMutex Type of the shared mutex object being wrapped + * + * \see SharedMutex, UniqueLock + * + * \ingroup CPP_BASE_MUTEX + */ +template +class SharedLock { + public: + /** + * Creates a lock without assigned shared mutex. + * + * A shared mutex can be assigned to the lock using the method Swap(). + */ + SharedLock(); + + /** + * Creates a lock from an unlocked shared mutex and locks it for reading. + * + * \pre \c shared_mutex is unlocked + * \post \c shared_mutex is locked for reading + * + * \param[IN] shared_mutex Shared mutex to be managed + */ + explicit SharedLock(SharedMutex& shared_mutex); + + /** + * Creates a lock from an unlocked shared mutex without locking it. + * + * \pre \c shared_mutex is unlocked + * \post \c shared_mutex is unlocked + * + * \param[IN] shared_mutex Shared mutex to be managed + * \param[IN] tag Tag to select correct constructor + */ + SharedLock(SharedMutex& shared_mutex, DeferLockTag tag); + + /** + * Creates a lock from an unlocked shared mutex and tries to lock it + * for reading. + * + * \pre \c shared_mutex is unlocked + * \post If successful, \c shared_mutex is locked for reading + * + * \param[IN] shared_mutex Shared mutex to be managed + * \param[IN] tag Tag to select correct constructor + */ + SharedLock(SharedMutex& shared_mutex, TryLockTag tag); + + /** + * Creates a lock from an already locked shared mutex. + * + * \pre \c shared_mutex is locked for reading + * \post \c shared_mutex is locked for reading + * + * \param[IN] shared_mutex Shared mutex to be managed + * \param[IN] tag Tag to select correct constructor + */ + SharedLock(SharedMutex& shared_mutex, AdoptLockTag tag); + + /** + * Unlocks the shared mutex if owned. + */ + ~SharedLock(); + + /** + * Waits until the shared mutex can be locked for reading and locks it. + * + * \throws ErrorException, if no shared mutex is set or it is already locked + */ + void LockShared(); + + /** + * Tries to lock the shared mutex for reading and returns immediately. + * + * \return \c true if shared mutex was locked for reading \n + * \c false otherwise + * + * \throws ErrorException, if no shared mutex is set or it is already locked + */ + bool TryLockShared(); + + /** + * Unlocks the shared mutex locked for reading. + * + * \throws ErrorException, if no shared mutex is set or it is not yet locked + */ + void UnlockShared(); + + /** + * Exchange shared mutex ownership with another shared lock + * + * \param other Shared lock to exchange ownership with + */ + void Swap(SharedLock& other); + + /** + * Gives up ownership of the shared mutex and returns a pointer to it. + * + * \return A pointer to the owned shared mutex. (If no shared mutex was + * owned, returns NULL). + */ + SharedMutex* Release(); + + /** + * Checks whether the shared mutex is owned and locked. + * + * \return \c true if shared mutex is locked, otherwise \c false. + */ + bool OwnsLock() const; + + private: + /** + * Disable copy construction and assignment. + */ + SharedLock(const SharedLock&); + SharedLock& operator=(const SharedLock&); + + /** Pointer to the owned shared mutex */ + SharedMutex* shared_mutex_; + /** Locked flag (is true if and only if the owned shared mutex is locked) */ + bool locked_; +}; + +} // namespace base +} // namespace embb + +#include + +#endif // EMBB_BASE_SHARED_MUTEX_H_ diff --git a/base_cpp/src/rwlock.cc b/base_cpp/src/rwlock.cc deleted file mode 100644 index 24dd2c6..0000000 --- a/base_cpp/src/rwlock.cc +++ /dev/null @@ -1,101 +0,0 @@ -/* - * Copyright (c) 2014-2015, Siemens AG. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ - -#include -#include - -namespace embb { -namespace base { - -RWLock::RWLock() - : rwlock_(), -// Disable "this is used in base member initializer" warning. -// We explicitly want this. -#ifdef EMBB_PLATFORM_COMPILER_MSVC -#pragma warning(push) -#pragma warning(disable:4355) -#endif - reader_lock_(*this), - writer_lock_(*this) { -#ifdef EMBB_PLATFORM_COMPILER_MSVC -#pragma warning(pop) -#endif - embb_rwlock_init(&rwlock_); -} - -RWLock::~RWLock() { - embb_rwlock_destroy(&rwlock_); -} - -void RWLock::LockRead() { - embb_rwlock_lock_read(&rwlock_); -} - -void RWLock::LockWrite() { - embb_rwlock_lock_write(&rwlock_); -} - -bool RWLock::TryLockRead() { - int result = embb_rwlock_try_lock_read(&rwlock_); - return result == EMBB_SUCCESS; -} - -bool RWLock::TryLockWrite() { - int result = embb_rwlock_try_lock_write(&rwlock_); - return result == EMBB_SUCCESS; -} - -void RWLock::UnlockRead() { - embb_rwlock_unlock_read(&rwlock_); -} - -void RWLock::UnlockWrite() { - embb_rwlock_unlock_write(&rwlock_); -} - -RWLock::ReaderLock::ReaderLock(RWLock& rwlock) : rwlock_(rwlock) {} -void RWLock::ReaderLock::Lock() { rwlock_.LockRead(); } -bool RWLock::ReaderLock::TryLock() { return rwlock_.TryLockRead(); } -void RWLock::ReaderLock::Unlock() { rwlock_.UnlockRead(); } - -RWLock::WriterLock::WriterLock(RWLock& rwlock) : rwlock_(rwlock) {} -void RWLock::WriterLock::Lock() { rwlock_.LockWrite(); } -bool RWLock::WriterLock::TryLock() { return rwlock_.TryLockWrite(); } -void RWLock::WriterLock::Unlock() { rwlock_.UnlockWrite(); } - -RWLock::ReaderLock& RWLock::GetReaderLock() { - return reader_lock_; -} -RWLock::WriterLock& RWLock::GetWriterLock() { - return writer_lock_; -} - -} // namespace base -} // namespace embb - - - - diff --git a/base_cpp/src/shared_mutex.cc b/base_cpp/src/shared_mutex.cc new file mode 100644 index 0000000..63f6978 --- /dev/null +++ b/base_cpp/src/shared_mutex.cc @@ -0,0 +1,73 @@ +/* + * Copyright (c) 2014-2015, Siemens AG. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include + +namespace embb { +namespace base { + +SharedMutex::SharedMutex() + : shared_mutex_() { + embb_shared_mutex_init(&shared_mutex_); +} + +SharedMutex::~SharedMutex() { + embb_shared_mutex_destroy(&shared_mutex_); +} + +void SharedMutex::Lock() { + embb_shared_mutex_lock(&shared_mutex_); +} + +bool SharedMutex::TryLock() { + int result = embb_shared_mutex_try_lock(&shared_mutex_); + return result == EMBB_SUCCESS; +} + +void SharedMutex::Unlock() { + embb_shared_mutex_unlock(&shared_mutex_); +} + +void SharedMutex::LockShared() { + embb_shared_mutex_lock_shared(&shared_mutex_); +} + +bool SharedMutex::TryLockShared() { + int result = embb_shared_mutex_try_lock_shared(&shared_mutex_); + return result == EMBB_SUCCESS; +} + +void SharedMutex::UnlockShared() { + embb_shared_mutex_unlock_shared(&shared_mutex_); +} + +} // namespace base +} // namespace embb + + + + diff --git a/base_cpp/test/main.cc b/base_cpp/test/main.cc index f25e976..ce56da7 100644 --- a/base_cpp/test/main.cc +++ b/base_cpp/test/main.cc @@ -34,7 +34,7 @@ #include #include #include -#include +#include #include @@ -46,7 +46,7 @@ using embb::base::test::ThreadSpecificStorageTest; using embb::base::test::AtomicTest; using embb::base::test::MemoryAllocationTest; using embb::base::test::ThreadTest; -using embb::base::test::RWLockTest; +using embb::base::test::SharedMutexTest; PT_MAIN("Base C++") { unsigned int max_threads = @@ -60,7 +60,7 @@ PT_MAIN("Base C++") { PT_RUN(AtomicTest); PT_RUN(MemoryAllocationTest); PT_RUN(ThreadTest); - PT_RUN(RWLockTest); + PT_RUN(SharedMutexTest); PT_EXPECT(embb_get_bytes_allocated() == 0); } diff --git a/base_cpp/test/rwlock_test.cc b/base_cpp/test/rwlock_test.cc deleted file mode 100644 index 088691b..0000000 --- a/base_cpp/test/rwlock_test.cc +++ /dev/null @@ -1,86 +0,0 @@ -/* - * Copyright (c) 2014-2015, Siemens AG. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ - -#include -#include -#include - -namespace embb { -namespace base { -namespace test { - -RWLockTest::RWLockTest() - : counter_(0), - num_threads_(partest::TestSuite::GetDefaultNumThreads()), - num_iterations_(partest::TestSuite::GetDefaultNumIterations()) { - CreateUnit("Shared read") - .Add(&RWLockTest::TestSharedRead_ThreadMethod, this, - num_threads_, num_iterations_); - CreateUnit("Exclusive write") - .Pre(&RWLockTest::TestExclusiveWrite_Pre, this) - .Add(&RWLockTest::TestExclusiveWrite_ReaderMethod, this, - num_threads_, num_iterations_) - .Add(&RWLockTest::TestExclusiveWrite_WriterMethod, this, - num_threads_, num_iterations_) - .Post(&RWLockTest::TestExclusiveWrite_Post, this); -} - -void RWLockTest::TestSharedRead_ThreadMethod() { - UniqueLock lock(rwlock_.GetReaderLock(), - embb::base::try_lock); - PT_ASSERT_EQ_MSG(lock.OwnsLock(), true, "Failed to lock for reading."); - - int spin = 10000; - while (--spin != 0); -} - -void RWLockTest::TestExclusiveWrite_Pre() { - counter_ = 0; -} - -void RWLockTest::TestExclusiveWrite_ReaderMethod() { - // Just add some contention - UniqueLock lock(rwlock_.GetReaderLock(), - embb::base::try_lock); - - int spin = 10000; - while (--spin != 0); -} - -void RWLockTest::TestExclusiveWrite_WriterMethod() { - UniqueLock lock(rwlock_.GetWriterLock()); - - ++counter_; -} - -void RWLockTest::TestExclusiveWrite_Post() { - PT_ASSERT_EQ_MSG(counter_, num_iterations_ * num_threads_, - "Counter value is inconsistent."); -} - -} // namespace test -} // namespace base -} // namespace embb diff --git a/base_cpp/test/rwlock_test.h b/base_cpp/test/rwlock_test.h deleted file mode 100644 index 47b10e4..0000000 --- a/base_cpp/test/rwlock_test.h +++ /dev/null @@ -1,63 +0,0 @@ -/* - * Copyright (c) 2014-2015, Siemens AG. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef BASE_CPP_TEST_RWLOCK_TEST_H_ -#define BASE_CPP_TEST_RWLOCK_TEST_H_ - -#include -#include -#include - - -namespace embb { -namespace base { -namespace test { - -class RWLockTest : public partest::TestCase { - public: - RWLockTest(); - - private: - void TestSharedRead_Pre(); - void TestSharedRead_ThreadMethod(); - void TestSharedRead_Post(); - - void TestExclusiveWrite_Pre(); - void TestExclusiveWrite_ReaderMethod(); - void TestExclusiveWrite_WriterMethod(); - void TestExclusiveWrite_Post(); - - RWLock rwlock_; - size_t counter_; - size_t num_threads_; - size_t num_iterations_; -}; - -} // namespace test -} // namespace base -} // namespace embb - -#endif // BASE_CPP_TEST_RWLOCK_TEST_H_ diff --git a/base_cpp/test/shared_mutex_test.cc b/base_cpp/test/shared_mutex_test.cc new file mode 100644 index 0000000..b4524a7 --- /dev/null +++ b/base_cpp/test/shared_mutex_test.cc @@ -0,0 +1,158 @@ +/* + * Copyright (c) 2014-2015, Siemens AG. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include +#include + +namespace embb { +namespace base { +namespace test { + +SharedMutexTest::SharedMutexTest() + : shared_mutex_(), + counter_(0), + num_threads_(partest::TestSuite::GetDefaultNumThreads()), + num_iterations_(partest::TestSuite::GetDefaultNumIterations()) { + CreateUnit("Shared read") + .Add(&SharedMutexTest::TestSharedRead_ThreadMethod, this, + num_threads_, num_iterations_); + CreateUnit("Exclusive write") + .Pre(&SharedMutexTest::TestExclusiveWrite_Pre, this) + .Add(&SharedMutexTest::TestExclusiveWrite_ReaderMethod, this, + num_threads_ / 2, num_iterations_) + .Add(&SharedMutexTest::TestExclusiveWrite_WriterMethod, this, + num_threads_ / 2, num_iterations_) + .Post(&SharedMutexTest::TestExclusiveWrite_Post, this); + CreateUnit("SharedLock") + .Add(&SharedMutexTest::TestSharedLock_ThreadMethod, this, + num_threads_, num_iterations_); +} + +void SharedMutexTest::TestSharedRead_ThreadMethod() { + SharedLock lock(shared_mutex_, embb::base::try_lock); + PT_ASSERT_EQ_MSG(lock.OwnsLock(), true, "Failed to lock for reading."); + + int spin = 10000; + while (--spin != 0); +} + +void SharedMutexTest::TestExclusiveWrite_Pre() { + counter_ = 0; +} + +void SharedMutexTest::TestExclusiveWrite_ReaderMethod() { + // Just add some contention + SharedLock lock(shared_mutex_, embb::base::try_lock); + + if (lock.OwnsLock()) { + int spin = 10000; + while (--spin != 0); + } +} + +void SharedMutexTest::TestExclusiveWrite_WriterMethod() { + UniqueLock lock(shared_mutex_); + + ++counter_; +} + +void SharedMutexTest::TestExclusiveWrite_Post() { + PT_ASSERT_EQ_MSG(counter_, num_iterations_ * (num_threads_ / 2), + "Counter value is inconsistent."); +} + +void SharedMutexTest::TestSharedLock_ThreadMethod() { + // Test basic usage + { + SharedLock<> lock(shared_mutex_); + PT_EXPECT_EQ(lock.OwnsLock(), true); + + lock.UnlockShared(); + PT_EXPECT_EQ(lock.OwnsLock(), false); + + lock.LockShared(); + PT_EXPECT_EQ(lock.OwnsLock(), true); + + lock.UnlockShared(); + PT_EXPECT_EQ(lock.OwnsLock(), false); + + bool locked_after_try = lock.TryLockShared(); + PT_EXPECT_EQ(locked_after_try, true); + PT_EXPECT_EQ(lock.OwnsLock(), true); + + lock.Release()->UnlockShared(); + PT_EXPECT_EQ(lock.OwnsLock(), false); + } + + // Test deferred lock construction + { + SharedLock<> lock(shared_mutex_, embb::base::defer_lock); + PT_EXPECT_EQ(lock.OwnsLock(), false); + } + + // Test try-lock construction + { + SharedLock<> lock(shared_mutex_, embb::base::try_lock); + PT_EXPECT_EQ(lock.OwnsLock(), true); + } + + // Test adopt lock construction + { + shared_mutex_.LockShared(); + SharedLock<> lock(shared_mutex_, embb::base::adopt_lock); + PT_EXPECT_EQ(lock.OwnsLock(), true); + } + + // Test lock swapping + { + SharedMutex another_mutex; + SharedLock<> lock1(another_mutex); + PT_EXPECT_EQ(lock1.OwnsLock(), true); + + { + SharedLock<> lock2(shared_mutex_); + PT_EXPECT_EQ(lock2.OwnsLock(), true); + + lock1.Swap(lock2); + PT_EXPECT_EQ(lock1.OwnsLock(), true); + PT_EXPECT_EQ(lock2.OwnsLock(), true); + } + + // At this point, lock2 was destroyed and "another_mutex" must be unlocked + SharedLock<> lock3(another_mutex, embb::base::try_lock); + PT_EXPECT_EQ(lock3.OwnsLock(), true); + + // But lock1 must still be locking "shared_mutex_" + PT_EXPECT_EQ(lock1.OwnsLock(), true); + lock1.Release()->UnlockShared(); + PT_EXPECT_EQ(lock1.OwnsLock(), false); + } +} + +} // namespace test +} // namespace base +} // namespace embb diff --git a/base_cpp/test/shared_mutex_test.h b/base_cpp/test/shared_mutex_test.h new file mode 100644 index 0000000..7b6df22 --- /dev/null +++ b/base_cpp/test/shared_mutex_test.h @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2014-2015, Siemens AG. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef BASE_CPP_TEST_SHARED_MUTEX_TEST_H_ +#define BASE_CPP_TEST_SHARED_MUTEX_TEST_H_ + +#include +#include +#include + + +namespace embb { +namespace base { +namespace test { + +class SharedMutexTest : public partest::TestCase { + public: + SharedMutexTest(); + + private: + void TestSharedRead_ThreadMethod(); + + void TestExclusiveWrite_Pre(); + void TestExclusiveWrite_ReaderMethod(); + void TestExclusiveWrite_WriterMethod(); + void TestExclusiveWrite_Post(); + + void TestSharedLock_ThreadMethod(); + + SharedMutex shared_mutex_; + size_t counter_; + size_t num_threads_; + size_t num_iterations_; +}; + +} // namespace test +} // namespace base +} // namespace embb + +#endif // BASE_CPP_TEST_SHARED_MUTEX_TEST_H_ -- libgit2 0.26.0