From b94cde8c1a1f28bde2e45610277a3150c0937f03 Mon Sep 17 00:00:00 2001 From: Francesco Romano Date: Sat, 21 Mar 2015 12:06:33 +0100 Subject: [PATCH] Added RecursiveLock Added also Lock interface (implemented by RecursiveLock and Mutex). LockGuard moved to used the generic Lock object instead of the Mutex --- src/libYARP_OS/CMakeLists.txt | 10 ++- src/libYARP_OS/include/yarp/os/Lock.h | 61 ++++++++++++++ src/libYARP_OS/include/yarp/os/LockGuard.h | 6 +- src/libYARP_OS/include/yarp/os/Mutex.h | 11 +-- .../include/yarp/os/RecursiveLock.h | 82 +++++++++++++++++++ src/libYARP_OS/include/yarp/os/all.h | 2 + .../include/yarp/os/impl/ACELockImpl.h | 44 ++++++++++ .../include/yarp/os/impl/CXX11LockImpl.h | 38 +++++++++ .../include/yarp/os/impl/LockImpl.h | 41 ++++++++++ .../include/yarp/os/impl/POSIXLockImpl.h | 50 +++++++++++ src/libYARP_OS/src/Lock.cpp | 3 + src/libYARP_OS/src/LockGuard.cpp | 12 +-- src/libYARP_OS/src/RecursiveLock.cpp | 43 ++++++++++ 13 files changed, 388 insertions(+), 15 deletions(-) create mode 100644 src/libYARP_OS/include/yarp/os/Lock.h create mode 100644 src/libYARP_OS/include/yarp/os/RecursiveLock.h create mode 100644 src/libYARP_OS/include/yarp/os/impl/ACELockImpl.h create mode 100644 src/libYARP_OS/include/yarp/os/impl/CXX11LockImpl.h create mode 100644 src/libYARP_OS/include/yarp/os/impl/LockImpl.h create mode 100644 src/libYARP_OS/include/yarp/os/impl/POSIXLockImpl.h create mode 100644 src/libYARP_OS/src/Lock.cpp create mode 100644 src/libYARP_OS/src/RecursiveLock.cpp diff --git a/src/libYARP_OS/CMakeLists.txt b/src/libYARP_OS/CMakeLists.txt index f1b3ec582e3..4de9e95fa36 100644 --- a/src/libYARP_OS/CMakeLists.txt +++ b/src/libYARP_OS/CMakeLists.txt @@ -31,6 +31,7 @@ set(YARP_OS_HDRS include/yarp/os/AbstractCarrier.h include/yarp/os/InputProtocol.h include/yarp/os/InputStream.h include/yarp/os/LocalReader.h + include/yarp/os/Lock.h include/yarp/os/LockGuard.h include/yarp/os/Log.h include/yarp/os/LogStream.h @@ -77,6 +78,7 @@ set(YARP_OS_HDRS include/yarp/os/AbstractCarrier.h include/yarp/os/Publisher.h include/yarp/os/Random.h include/yarp/os/RateThread.h + include/yarp/os/RecursiveLock.h include/yarp/os/ResourceFinder.h include/yarp/os/ResourceFinderOptions.h include/yarp/os/RFModule.h @@ -131,12 +133,14 @@ set(YARP_OS_IDL_HDRS include/yarp/os/idl/BareStyle.h include/yarp/os/idl/WireVocab.h include/yarp/os/idl/WireWriter.h) -set(YARP_OS_IMPL_HDRS include/yarp/os/impl/ACESemaphoreImpl.h +set(YARP_OS_IMPL_HDRS include/yarp/os/impl/ACELockImpl.h + include/yarp/os/impl/ACESemaphoreImpl.h include/yarp/os/impl/AuthHMAC.h include/yarp/os/impl/BottleImpl.h include/yarp/os/impl/BufferedConnectionWriter.h include/yarp/os/impl/Carriers.h include/yarp/os/impl/Companion.h + include/yarp/os/impl/CXX11LockImpl.h include/yarp/os/impl/CXX11SemaphoreImpl.h include/yarp/os/impl/DgramTwoWayStream.h include/yarp/os/impl/Dispatcher.h @@ -149,6 +153,7 @@ set(YARP_OS_IMPL_HDRS include/yarp/os/impl/ACESemaphoreImpl.h include/yarp/os/impl/HttpCarrier.h include/yarp/os/impl/IOException.h include/yarp/os/impl/LocalCarrier.h + include/yarp/os/impl/LockImpl.h include/yarp/os/impl/Logger.h include/yarp/os/impl/LogImpl.h include/yarp/os/impl/LogForwarder.h @@ -177,6 +182,7 @@ set(YARP_OS_IMPL_HDRS include/yarp/os/impl/ACESemaphoreImpl.h include/yarp/os/impl/PortCorePackets.h include/yarp/os/impl/PortCoreUnit.h include/yarp/os/impl/PortManager.h + include/yarp/os/impl/POSIXLockImpl.h include/yarp/os/impl/POSIXSemaphoreImpl.h include/yarp/os/impl/Protocol.h include/yarp/os/impl/RunCheckpoints.h @@ -233,6 +239,7 @@ set(YARP_OS_SRCS src/AbstractCarrier.cpp src/IConfig.cpp src/InputStream.cpp src/LocalCarrier.cpp + src/Lock.cpp src/LockGuard.cpp src/Log.cpp src/Logger.cpp @@ -286,6 +293,7 @@ set(YARP_OS_SRCS src/AbstractCarrier.cpp src/Protocol.cpp src/Random.cpp src/RateThread.cpp + src/RecursiveLock.cpp src/ResourceFinder.cpp src/ResourceFinderOptions.cpp src/RFModule.cpp diff --git a/src/libYARP_OS/include/yarp/os/Lock.h b/src/libYARP_OS/include/yarp/os/Lock.h new file mode 100644 index 00000000000..6cfc0c049fa --- /dev/null +++ b/src/libYARP_OS/include/yarp/os/Lock.h @@ -0,0 +1,61 @@ +// -*- mode:C++; tab-width:4; c-basic-offset:4; indent-tabs-mode:nil -*- + +/* + * Copyright (C) 2015 Robotics and Cognitive Sciences Department. IIT + * Authors: Francesco Romano + * CopyPolicy: Released under the terms of the LGPLv2.1 or later, see LGPL.TXT + * + */ + +#ifndef YARP_LOCK_H +#define YARP_LOCK_H + +#include + +namespace yarp { + namespace os { + class Lock; + } +} +/** + * This interface defines the Lock object. + * A Lock is a synchronization primitive that can be used to protect shared data from being + * simultaneously accessed by multiple threads. + * + * + */ +class YARP_OS_API yarp::os::Lock +{ +public: + virtual ~Lock(); + + /** + * @brief Lock the associated resource, waiting if the resource is busy. + * + * See the actual implementation documentation for the correct use + */ + virtual void lock() = 0; + + /** + * @brief Lock the associated resource if it is free. + * + * If the lock is successfully taken returns true, otherwise returns false + * and no lock is taken. + * See the actual implementation documentation for the correct use + * + * @return true if the associated resource was successfully locked. + * + */ + virtual bool tryLock() = 0; + + /** + * @brief Unlock the associated resource thus freeing waiting threads. + * + * See the actual implementation documentation for the correct use + * + */ + virtual void unlock() = 0; +}; + + +#endif /* end of include guard: YARP_LOCK_H */ diff --git a/src/libYARP_OS/include/yarp/os/LockGuard.h b/src/libYARP_OS/include/yarp/os/LockGuard.h index 4152d2e57db..40cda9bddc5 100644 --- a/src/libYARP_OS/include/yarp/os/LockGuard.h +++ b/src/libYARP_OS/include/yarp/os/LockGuard.h @@ -14,7 +14,7 @@ namespace yarp { namespace os { - class Mutex; + class Lock; class LockGuard; } } @@ -34,7 +34,7 @@ class YARP_OS_API yarp::os::LockGuard { * The behavior is undefined if _mutex is destroyed before the LockGuard object is. * @param _mutex the mutex which will be locked */ - explicit LockGuard(yarp::os::Mutex& _mutex); + explicit LockGuard(yarp::os::Lock& _lock); /** * destructs the LockGuard object, unlocks the underlying mutex @@ -49,7 +49,7 @@ class YARP_OS_API yarp::os::LockGuard { /** Assignment operator is disabled */ LockGuard& operator=(const LockGuard&); - yarp::os::Mutex& mutex; /*!< underlining mutex */ + yarp::os::Lock& lock; /*!< underlining mutex */ }; #endif diff --git a/src/libYARP_OS/include/yarp/os/Mutex.h b/src/libYARP_OS/include/yarp/os/Mutex.h index 0c120ede16f..5e096f006f6 100644 --- a/src/libYARP_OS/include/yarp/os/Mutex.h +++ b/src/libYARP_OS/include/yarp/os/Mutex.h @@ -11,6 +11,7 @@ #define _YARP2_MUTEX_ #include +#include namespace yarp { namespace os { @@ -25,7 +26,7 @@ namespace yarp { * C++11, for eventual replacement by that class. * */ -class YARP_OS_API yarp::os::Mutex { +class YARP_OS_API yarp::os::Mutex : public yarp::os::Lock { public: /** @@ -40,7 +41,7 @@ class YARP_OS_API yarp::os::Mutex { * Destructor. * */ - ~Mutex(); + virtual ~Mutex(); /** * @@ -49,7 +50,7 @@ class YARP_OS_API yarp::os::Mutex { * the resource. * */ - void lock(); + virtual void lock(); /** * @@ -60,7 +61,7 @@ class YARP_OS_API yarp::os::Mutex { * @return true if the associated resource was successfully locked. * */ - bool tryLock(); + virtual bool tryLock(); /** * @@ -69,7 +70,7 @@ class YARP_OS_API yarp::os::Mutex { * the behavior is undefined. * */ - void unlock(); + virtual void unlock(); private: void *implementation; }; diff --git a/src/libYARP_OS/include/yarp/os/RecursiveLock.h b/src/libYARP_OS/include/yarp/os/RecursiveLock.h new file mode 100644 index 00000000000..792179557f4 --- /dev/null +++ b/src/libYARP_OS/include/yarp/os/RecursiveLock.h @@ -0,0 +1,82 @@ +// -*- mode:C++; tab-width:4; c-basic-offset:4; indent-tabs-mode:nil -*- + +/* + * Copyright (C) 2015 Robotics and Cognitive Sciences Department. IIT + * Authors: Francesco Romano + * CopyPolicy: Released under the terms of the LGPLv2.1 or later, see LGPL.TXT + * + */ + +#ifndef YARP_RECURSIVELOCK_H +#define YARP_RECURSIVELOCK_H + +#include "Lock.h" + +namespace yarp { + namespace os { + class RecursiveLock; + } +} + +/** + * RecursiveLock offers exclusive, recursive ownership semantics: + * - A calling thread owns a RecursiveLock for a period of time that starts when it successfully calls either lock or tryLock. During this period, the thread may make additional calls to lock or tryLock. The period of ownership ends when the thread makes a matching number of calls to unlock. + * - When a thread owns a RecursiveLock, all other threads will block (for calls to lock) or receive a false return value (for tryLock) if they attempt to claim ownership of the RecursiveLock. + * The behavior of a program is undefined if a RecursiveLock is destroyed while still owned by some thread. + * The behavior of a program is undefined if a RecursiveLock is unlocked by a thread which is not + * currently owning the RecursiveLock + * + */ +class YARP_OS_API yarp::os::RecursiveLock : public yarp::os::Lock { +public: + + /** + * + * Constructor. + * + */ + RecursiveLock(); + + /** + * + * Destructor. + * + */ + virtual ~RecursiveLock(); + + /** + * @brief Lock the associated resource, waiting if the resource is busy. + * + * If the thread which is currently owning the resource calls + * this function, it will not block, and a reference count will be increased + * Thu number of calls to lock() must be balanced by the same number of + * calls to unlock() + * + */ + virtual void lock(); + + /** + * @brief Lock the associated resource if it is free. + * + * @see RecursiveLock#lock() for more detailed description + * @return true if the associated resource was successfully locked. False otherwise + * + */ + virtual bool tryLock(); + + /** + * @brief Unlock the associated resource thus freeing waiting threads. + * + * If the resource is not currently locked by the calling thread, + * the behavior is undefined. + * + */ + virtual void unlock(); + +private: + void *implementation; +}; + + +#endif /* end of include guard: YARP_RECURSIVELOCK_H */ + diff --git a/src/libYARP_OS/include/yarp/os/all.h b/src/libYARP_OS/include/yarp/os/all.h index 18204a69316..3035fa31a60 100644 --- a/src/libYARP_OS/include/yarp/os/all.h +++ b/src/libYARP_OS/include/yarp/os/all.h @@ -50,6 +50,8 @@ #include #include #include +#include +#include #include #include #include diff --git a/src/libYARP_OS/include/yarp/os/impl/ACELockImpl.h b/src/libYARP_OS/include/yarp/os/impl/ACELockImpl.h new file mode 100644 index 00000000000..e6bde6722f4 --- /dev/null +++ b/src/libYARP_OS/include/yarp/os/impl/ACELockImpl.h @@ -0,0 +1,44 @@ +// -*- mode:C++; tab-width:4; c-basic-offset:4; indent-tabs-mode:nil -*- + +/* + * Copyright (C) 2015 Robotics and Cognitive Sciences Department. IIT + * Authors: Francesco Romano + * CopyPolicy: Released under the terms of the LGPLv2.1 or later, see LGPL.TXT + * + */ + +#ifndef YARP_ACELOCKIMPL_H +#define YARP_ACELOCKIMPL_H + +#include +#include + +class YARP_OS_impl_API yarp::os::impl::RecursiveLockImpl { +public: + void lock() { + int result = mutex.acquire(); + if (result != -1) return; + yError("Mutex lock failed (errno %d)", ACE_OS::last_error()); + } + + bool tryLock() { + int result = mutex.tryacquire(); + if (result != -1) return true; + //if errno is EBUSY this is a "clean" failure: lock is busy + if (ACE_OS::last_error() == EBUSY) return false; + //different error: return false and print error + yError("Mutex tryLock failed (errno %d)", ACE_OS::last_error()); + return false; + + } + + // unlock + void unlock() { + mutex.release(); + } + +private: + ACE_Recursive_Thread_Mutex mutex; +}; + +#endif /* end of include guard: YARP_ACELOCKIMPL_H */ diff --git a/src/libYARP_OS/include/yarp/os/impl/CXX11LockImpl.h b/src/libYARP_OS/include/yarp/os/impl/CXX11LockImpl.h new file mode 100644 index 00000000000..2313d2decd6 --- /dev/null +++ b/src/libYARP_OS/include/yarp/os/impl/CXX11LockImpl.h @@ -0,0 +1,38 @@ +// -*- mode:C++; tab-width:4; c-basic-offset:4; indent-tabs-mode:nil -*- + +/* + * Copyright (C) 2015 Robotics and Cognitive Sciences Department. IIT + * Authors: Francesco Romano + * CopyPolicy: Released under the terms of the LGPLv2.1 or later, see LGPL.TXT + * + */ + +#ifndef YARP_CXX11LOCKIMPL_H +#define YARP_CXX11LOCKIMPL_H + +#include + +class YARP_OS_impl_API yarp::os::impl::RecursiveLockImpl { +public: + RecursiveLockImpl() {} + RecursiveLockImpl(RecursiveLockImpl&) = delete; + RecursiveLockImpl& operator= (RecursiveLockImpl&) = delete; + + void lock() { + mutex.lock(); + } + + bool tryLock() { + return mutex.try_lock(); + } + + // increment + void unlock() { + mutex.unlock(); + } + +private: + std::recursive_mutex mutex; +}; + +#endif /* end of include guard: YARP_CXX11LOCKIMPL_H */ diff --git a/src/libYARP_OS/include/yarp/os/impl/LockImpl.h b/src/libYARP_OS/include/yarp/os/impl/LockImpl.h new file mode 100644 index 00000000000..eaf6977c3f4 --- /dev/null +++ b/src/libYARP_OS/include/yarp/os/impl/LockImpl.h @@ -0,0 +1,41 @@ +// -*- mode:C++; tab-width:4; c-basic-offset:4; indent-tabs-mode:nil -*- + +/* + * Copyright (C) 2015 Robotics and Cognitive Sciences Department. IIT + * Authors: Francesco Romano + * CopyPolicy: Released under the terms of the LGPLv2.1 or later, see LGPL.TXT + * + */ + +#ifndef YARP_LOCKIMPL_H +#define YARP_LOCKIMPL_H + +// Pre-declare Recursive Lock +namespace yarp { + namespace os { + namespace impl { + class RecursiveLockImpl; + } + } +} + +//Decide which implementation to use +#include + +#ifdef YARP_HAS_CXX11 +# include +#else +# if defined(__linux__) || defined(__APPLE__) +# include +# else +// For everything else, there's ACE +# ifdef YARP_HAS_ACE +# include +# else +# error Cannot implement semaphores +# endif +# endif +#endif + +#endif /* end of include guard: YARP_LOCKIMPL_H */ + diff --git a/src/libYARP_OS/include/yarp/os/impl/POSIXLockImpl.h b/src/libYARP_OS/include/yarp/os/impl/POSIXLockImpl.h new file mode 100644 index 00000000000..95af1ce9863 --- /dev/null +++ b/src/libYARP_OS/include/yarp/os/impl/POSIXLockImpl.h @@ -0,0 +1,50 @@ +// -*- mode:C++; tab-width:4; c-basic-offset:4; indent-tabs-mode:nil -*- + +/* + * Copyright (C) 2015 Robotics and Cognitive Sciences Department. IIT + * Authors: Francesco Romano + * CopyPolicy: Released under the terms of the LGPLv2.1 or later, see LGPL.TXT + * + */ + +#ifndef YARP_POSIXLOCKIMPL_H +#define YARP_POSIXLOCKIMPL_H + +#include +#include + +class YARP_OS_impl_API yarp::os::impl::RecursiveLockImpl { +public: + RecursiveLockImpl() + { + pthread_mutexattr_t attributes; + yAssert(pthread_mutexattr_init(&attributes) == 0); + yAssert(pthread_mutexattr_settype(&attributes, PTHREAD_MUTEX_RECURSIVE) == 0); + yAssert(pthread_mutex_init(&mutex, &attributes) == 0); + yAssert(pthread_mutexattr_destroy(&attributes) == 0); + } + + virtual ~RecursiveLockImpl() { + pthread_mutex_destroy(&mutex); + } + + // blocking wait + void lock() { + pthread_mutex_lock(&mutex); + } + + bool tryLock() { + return pthread_mutex_trylock(&mutex) == 0; + } + + // increment + void unlock() { + pthread_mutex_unlock(&mutex); + } + +private: + pthread_mutex_t mutex; +}; + + +#endif /* end of include guard: YARP_POSIXLOCKIMPL_H */ diff --git a/src/libYARP_OS/src/Lock.cpp b/src/libYARP_OS/src/Lock.cpp new file mode 100644 index 00000000000..747b819f110 --- /dev/null +++ b/src/libYARP_OS/src/Lock.cpp @@ -0,0 +1,3 @@ +#include + +yarp::os::Lock::~Lock() {} diff --git a/src/libYARP_OS/src/LockGuard.cpp b/src/libYARP_OS/src/LockGuard.cpp index 6f577691ce2..44ce979f52a 100644 --- a/src/libYARP_OS/src/LockGuard.cpp +++ b/src/libYARP_OS/src/LockGuard.cpp @@ -8,23 +8,23 @@ */ #include -#include +#include namespace yarp { namespace os { - LockGuard::LockGuard(yarp::os::Mutex& _mutex) - : mutex(_mutex) + LockGuard::LockGuard(yarp::os::Lock& _lock) + : lock(_lock) { - mutex.lock(); + lock.lock(); } LockGuard::~LockGuard() { - mutex.unlock(); + lock.unlock(); } LockGuard::LockGuard(const LockGuard& lg) - : mutex(lg.mutex) { } + : lock(lg.lock) { } LockGuard& LockGuard::operator=(const LockGuard&) { return *this; } } diff --git a/src/libYARP_OS/src/RecursiveLock.cpp b/src/libYARP_OS/src/RecursiveLock.cpp new file mode 100644 index 00000000000..e2f4a959a86 --- /dev/null +++ b/src/libYARP_OS/src/RecursiveLock.cpp @@ -0,0 +1,43 @@ +// -*- mode:C++; tab-width:4; c-basic-offset:4; indent-tabs-mode:nil -*- + +/* + * Copyright (C) 2015 Robotics and Cognitive Sciences Department. IIT + * Authors: Francesco Romano + * CopyPolicy: Released under the terms of the LGPLv2.1 or later, see LGPL.TXT + * + */ + +#include +#include +#include + +using namespace yarp::os::impl; +using namespace yarp::os; + +RecursiveLock::RecursiveLock() { + implementation = new RecursiveLockImpl(); + yAssert(implementation!=NULL); +} + +RecursiveLock::~RecursiveLock() { + RecursiveLockImpl *lock = static_cast(implementation); + if (lock) { + delete lock; + implementation = NULL; + } +} + +void RecursiveLock::lock() { + RecursiveLockImpl *lock = static_cast(implementation); + lock->lock(); +} + +bool RecursiveLock::tryLock() { + RecursiveLockImpl *lock = static_cast(implementation); + return lock->tryLock(); +} + +void RecursiveLock::unlock() { + RecursiveLockImpl *lock = static_cast(implementation); + lock->unlock(); +}