Add C++ wrappers for pthread mutex and rcu read lock
authorJérémie Galarneau <jeremie.galarneau@efficios.com>
Thu, 5 May 2022 19:16:53 +0000 (15:16 -0400)
committerJérémie Galarneau <jeremie.galarneau@efficios.com>
Mon, 13 Jun 2022 20:34:46 +0000 (16:34 -0400)
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 <jeremie.galarneau@efficios.com>
Change-Id: I26cfc2e954d1d4cc1f7e0973cdcd1b9881ef181a

src/common/Makefile.am
src/common/pthread-lock.hpp [new file with mode: 0644]
src/common/urcu.hpp [new file with mode: 0644]

index 0a5e5a8f11dea0574955942dd3131e4812cbe478..4df84d6985b3ceff88b90850d70970b80cd9d9e0 100644 (file)
@@ -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 (file)
index 0000000..35fde09
--- /dev/null
@@ -0,0 +1,90 @@
+/*
+ * Copyright (C) 2022 Jérémie Galarneau <jeremie.galarneau@efficios.com>
+ *
+ * SPDX-License-Identifier: LGPL-2.1-only
+ *
+ */
+
+#ifndef LTTNG_PTHREAD_LOCK_H
+#define LTTNG_PTHREAD_LOCK_H
+
+#include <common/exception.hpp>
+
+#include <pthread.h>
+#include <mutex>
+
+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<details::mutex> _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 (file)
index 0000000..2ea2001
--- /dev/null
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2022 Jérémie Galarneau <jeremie.galarneau@efficios.com>
+ *
+ * SPDX-License-Identifier: LGPL-2.1-only
+ *
+ */
+
+#ifndef LTTNG_URCU_H
+#define LTTNG_URCU_H
+
+#define _LGPL_SOURCE
+#include <urcu.h>
+#include <mutex>
+
+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<details::read_lock> _guard;
+};
+
+} /* namespace urcu */
+} /* namespace lttng */
+
+#endif /* LTTNG_URCU_H */
This page took 0.029048 seconds and 5 git commands to generate.