From: Jérémie Galarneau Date: Thu, 5 May 2022 19:16:53 +0000 (-0400) Subject: Add C++ wrappers for pthread mutex and rcu read lock X-Git-Url: https://git.lttng.org./?a=commitdiff_plain;h=0a325f4dec3f6d553dad5d2c26ebfdc78201c363;p=lttng-tools.git Add C++ wrappers for pthread mutex and rcu read lock Add two wrappers that are similar and provide the "Mutex" named requirements[1] around pthread_mutex_t and liburcu's RCU reader lock. In both cases, the intention is to either use the `mutex` or `read_lock` interface with the standard concurrency support library (e.g. std::lock, etc.) or, more likely, use the lock_guard wrappers. The lock_guard[2] wrappers make it easier to convert existing code to be exception-safe and generally makes the use of those locks less error-prone. [1] https://en.cppreference.com/w/cpp/named_req/Mutex [2] https://en.cppreference.com/w/cpp/thread/lock_guard Signed-off-by: Jérémie Galarneau Change-Id: I26cfc2e954d1d4cc1f7e0973cdcd1b9881ef181a --- diff --git a/src/common/Makefile.am b/src/common/Makefile.am index 0a5e5a8f1..4df84d698 100644 --- a/src/common/Makefile.am +++ b/src/common/Makefile.am @@ -94,6 +94,7 @@ libcommon_lgpl_la_SOURCES = \ notification.cpp \ payload.cpp payload.hpp \ payload-view.cpp payload-view.hpp \ + pthread-lock.hpp \ readwrite.cpp readwrite.hpp \ runas.cpp runas.hpp \ session-descriptor.cpp \ @@ -106,6 +107,7 @@ libcommon_lgpl_la_SOURCES = \ unix.cpp unix.hpp \ uri.cpp uri.hpp \ userspace-probe.cpp \ + urcu.hpp \ utils.cpp utils.hpp if HAVE_ELF_H diff --git a/src/common/pthread-lock.hpp b/src/common/pthread-lock.hpp new file mode 100644 index 000000000..35fde097c --- /dev/null +++ b/src/common/pthread-lock.hpp @@ -0,0 +1,90 @@ +/* + * Copyright (C) 2022 Jérémie Galarneau + * + * SPDX-License-Identifier: LGPL-2.1-only + * + */ + +#ifndef LTTNG_PTHREAD_LOCK_H +#define LTTNG_PTHREAD_LOCK_H + +#include + +#include +#include + +namespace lttng { +namespace pthread { + +namespace details { +/* + * Class wrapping pthread mutexes and satisfying the Mutex named requirements, except + * for the "Default Constructible" requirement. The class is not default-constructible since the + * intention is to ease the transition of existing C-code using pthread mutexes to idiomatic C++. + * + * New code should use std::mutex. + */ +class mutex { +public: + mutex(pthread_mutex_t& mutex_p) : _mutex{mutex_p} + { + } + + /* "Not copyable" and "not moveable" Mutex requirements. */ + mutex(mutex const &) = delete; + mutex &operator=(mutex const &) = delete; + + void lock() + { + if (pthread_mutex_lock(&_mutex) != 0) { + LTTNG_THROW_POSIX("Failed to lock mutex", errno); + } + } + + bool try_lock() + { + const auto ret = pthread_mutex_trylock(&_mutex); + + if (ret == 0) { + return true; + } else if (errno == EBUSY || errno == EAGAIN) { + return false; + } else { + LTTNG_THROW_POSIX("Failed to try to lock mutex", errno); + } + } + + void unlock() + { + if (pthread_mutex_unlock(&_mutex) != 0) { + LTTNG_THROW_POSIX("Failed to unlock mutex", errno); + } + } + +private: + pthread_mutex_t& _mutex; +}; +} /* namespace details */ + +/* + * Provides the basic concept of std::lock_guard for posix mutexes. + * + * `lock` is held for the duration of lock_guard's lifetime. + */ +class lock_guard { +public: + lock_guard(pthread_mutex_t& mutex) : _mutex{mutex}, _guard(_mutex) + { + } + + lock_guard(const lock_guard &) = delete; + +private: + details::mutex _mutex; + std::lock_guard _guard; +}; + +} /* namespace pthread */ +} /* namespace lttng */ + +#endif /* LTTNG_PTHREAD_LOCK_H */ diff --git a/src/common/urcu.hpp b/src/common/urcu.hpp new file mode 100644 index 000000000..2ea2001cd --- /dev/null +++ b/src/common/urcu.hpp @@ -0,0 +1,74 @@ +/* + * Copyright (C) 2022 Jérémie Galarneau + * + * SPDX-License-Identifier: LGPL-2.1-only + * + */ + +#ifndef LTTNG_URCU_H +#define LTTNG_URCU_H + +#define _LGPL_SOURCE +#include +#include + +namespace lttng { +namespace urcu { + +namespace details { +/* + * Wrapper around an urcu read lock which satisfies the 'Mutex' named + * requirements of C++11. Satisfying those requirements facilitates the use of + * standard concurrency support library facilities. + * + * read_lock is under the details namespace since it is unlikely to be used + * directly by exception-safe code. See read_lock_guard. + */ +class read_lock { +public: + read_lock() = default; + + /* "Not copyable" and "not moveable" Mutex requirements. */ + read_lock(read_lock const &) = delete; + read_lock &operator=(read_lock const &) = delete; + + void lock() + { + rcu_read_lock(); + } + + bool try_lock() + { + lock(); + return true; + } + + void unlock() + { + rcu_read_unlock(); + } +}; +} /* namespace details */ + +/* + * Provides the basic concept of std::lock_guard for rcu reader locks. + * + * The RCU reader lock is held for the duration of lock_guard's lifetime. + */ +class read_lock_guard { +public: + read_lock_guard() : _guard(_lock) + { + } + + read_lock_guard(const read_lock_guard &) = delete; + +private: + details::read_lock _lock; + std::lock_guard _guard; +}; + +} /* namespace urcu */ +} /* namespace lttng */ + +#endif /* LTTNG_URCU_H */