error-query.cpp \
evaluation.cpp \
event.cpp \
+ eventfd.hpp eventfd.cpp \
event-expr/event-expr.cpp \
event-field-value.cpp \
event-rule/event-rule.cpp \
event-rule/jul-logging.cpp \
event-rule/python-logging.cpp \
exception.cpp exception.hpp \
- file-descriptor.hpp \
+ file-descriptor.hpp file-descriptor.cpp \
fd-handle.cpp fd-handle.hpp\
format.hpp \
kernel-probe.cpp \
--- /dev/null
+/*
+ * Copyright (C) 2023 Jérémie Galarneau <jeremie.galarneau@efficios.com>
+ *
+ * SPDX-License-Identifier: LGPL-2.1-only
+ *
+ */
+
+#include "eventfd.hpp"
+
+#include <common/exception.hpp>
+#include <common/format.hpp>
+#include <common/readwrite.hpp>
+
+#include <sys/eventfd.h>
+
+lttng::eventfd::eventfd(bool use_semaphore_semantics, std::uint64_t initial_value) :
+ file_descriptor([use_semaphore_semantics, initial_value]() {
+ int flags = ::EFD_CLOEXEC;
+
+ if (use_semaphore_semantics) {
+ flags |= ::EFD_SEMAPHORE;
+ }
+
+ const auto raw_fd = ::eventfd(initial_value, flags);
+ if (raw_fd < 0) {
+ LTTNG_THROW_POSIX("Failed to create eventfd", errno);
+ }
+
+ return raw_fd;
+ }())
+{
+}
+
+void lttng::eventfd::increment(std::uint64_t value)
+{
+ try {
+ write(&value, sizeof(value));
+ } catch (const std::exception& e) {
+ LTTNG_THROW_ERROR(fmt::format("Failed to increment eventfd: {}", e.what()));
+ }
+}
+
+std::uint64_t lttng::eventfd::decrement()
+{
+ std::uint64_t value;
+
+ try {
+ read(&value, sizeof(value));
+ } catch (const std::exception& e) {
+ LTTNG_THROW_ERROR(fmt::format("Failed to decrement eventfd: {}", e.what()));
+ }
+
+ return value;
+}
--- /dev/null
+/*
+ * Copyright (C) 2023 Jérémie Galarneau <jeremie.galarneau@efficios.com>
+ *
+ * SPDX-License-Identifier: LGPL-2.1-only
+ *
+ */
+
+#ifndef LTTNG_EVENTFD_HPP
+#define LTTNG_EVENTFD_HPP
+
+#include <common/file-descriptor.hpp>
+
+#include <cstdint>
+
+namespace lttng {
+
+class eventfd : public file_descriptor {
+public:
+ /* Throws a posix_error exception on failure to create the underlying resource. */
+ eventfd(bool use_semaphore_semantics = true, std::uint64_t initial_value = 0);
+ eventfd(const eventfd&) = delete;
+ eventfd& operator=(const eventfd&) = delete;
+ eventfd(eventfd&&) = delete;
+ void operator=(eventfd&&) = delete;
+
+ /* Throws on error. */
+ void increment(std::uint64_t value = 1);
+ /*
+ * Note that decrement() will block if the underlying value of the eventfd is 0 when
+ * semaphore semantics are used, see EVENTFD(2).
+ *
+ * decrement() returns the new value of the underlying counter of the eventfd.
+ *
+ * Throws on error.
+ */
+ std::uint64_t decrement();
+};
+
+} /* namespace lttng */
+
+#endif /* LTTNG_EVENTFD_HPP */
--- /dev/null
+/*
+ * Copyright (C) 2023 Jérémie Galarneau <jeremie.galarneau@efficios.com>
+ *
+ * SPDX-License-Identifier: LGPL-2.1-only
+ *
+ */
+
+#include "file-descriptor.hpp"
+
+#include <common/error.hpp>
+#include <common/exception.hpp>
+#include <common/format.hpp>
+#include <common/readwrite.hpp>
+
+#include <algorithm>
+#include <limits>
+#include <unistd.h>
+
+namespace {
+bool is_valid_fd(int fd)
+{
+ return fd >= 0;
+}
+} // anonymous namespace
+
+lttng::file_descriptor::file_descriptor() noexcept
+{
+}
+
+lttng::file_descriptor::file_descriptor(int raw_fd) noexcept : _raw_fd{ raw_fd }
+{
+ LTTNG_ASSERT(is_valid_fd(_raw_fd));
+}
+
+lttng::file_descriptor::file_descriptor(lttng::file_descriptor&& other) noexcept
+{
+ std::swap(_raw_fd, other._raw_fd);
+}
+
+lttng::file_descriptor& lttng::file_descriptor::operator=(lttng::file_descriptor&& other) noexcept
+{
+ _cleanup();
+ std::swap(_raw_fd, other._raw_fd);
+ return *this;
+}
+
+lttng::file_descriptor::~file_descriptor() noexcept
+{
+ _cleanup();
+}
+
+int lttng::file_descriptor::_fd() const noexcept
+{
+ LTTNG_ASSERT(is_valid_fd(_raw_fd));
+ return _raw_fd;
+}
+
+void lttng::file_descriptor::_cleanup() noexcept
+{
+ if (!is_valid_fd(_raw_fd)) {
+ return;
+ }
+
+ const auto ret = ::close(_raw_fd);
+
+ _raw_fd = -1;
+ if (ret) {
+ PERROR("Failed to close file descriptor: fd=%i", _raw_fd);
+ }
+}
+
+void lttng::file_descriptor::write(const void *buffer, std::size_t size)
+{
+ /*
+ * This is a limitation of the internal helper that is not a problem in practice for the
+ * moment.
+ */
+ using lttng_write_return_type = decltype(lttng_write(
+ std::declval<int>(), std::declval<const void *>(), std::declval<size_t>()));
+ constexpr auto max_supported_write_size =
+ std::numeric_limits<lttng_write_return_type>::max();
+
+ if (size > max_supported_write_size) {
+ LTTNG_THROW_UNSUPPORTED_ERROR(fmt::format(
+ "Write size exceeds the maximal supported value of lttng_write: write_size={}, maximal_write_size={}",
+ size,
+ max_supported_write_size));
+ }
+
+ const auto write_ret = lttng_write(_fd(), buffer, size);
+ if (write_ret < 0 || static_cast<std::size_t>(write_ret) != size) {
+ LTTNG_THROW_POSIX(fmt::format("Failed to write to file descriptor: fd={}", _fd()),
+ errno);
+ }
+}
+
+void lttng::file_descriptor::read(void *buffer, std::size_t size)
+{
+ /*
+ * This is a limitation of the internal helper that is not a problem in practice for the
+ * moment.
+ */
+ using lttng_read_return_type = decltype(lttng_read(
+ std::declval<int>(), std::declval<void *>(), std::declval<size_t>()));
+ constexpr auto max_supported_read_size = std::numeric_limits<lttng_read_return_type>::max();
+
+ if (size > max_supported_read_size) {
+ LTTNG_THROW_UNSUPPORTED_ERROR(fmt::format(
+ "Read size exceeds the maximal supported value of lttng_read: read_size={}, maximal_read_size={}",
+ size,
+ max_supported_read_size));
+ }
+
+ const auto read_ret = lttng_read(_fd(), buffer, size);
+ if (read_ret < 0 || static_cast<std::size_t>(read_ret) != size) {
+ LTTNG_THROW_POSIX(fmt::format("Failed to read from file descriptor: fd={}", _fd()),
+ errno);
+ }
+}
#ifndef LTTNG_FILE_DESCRIPTOR_HPP
#define LTTNG_FILE_DESCRIPTOR_HPP
-#include <common/error.hpp>
-#include <common/format.hpp>
-
-#include <algorithm>
-
-#include <unistd.h>
+#include <cstddef>
namespace lttng {
-/*
- * RAII wrapper around a UNIX file descriptor. A file_descriptor's underlying
- * file descriptor.
- */
+/* RAII wrapper around a UNIX file descriptor. */
class file_descriptor {
public:
- file_descriptor()
- {
- }
-
- explicit file_descriptor(int raw_fd) noexcept : _raw_fd{ raw_fd }
- {
- LTTNG_ASSERT(_is_valid_fd(_raw_fd));
- }
+ file_descriptor() noexcept;
+ explicit file_descriptor(int raw_fd) noexcept;
file_descriptor(const file_descriptor&) = delete;
file_descriptor& operator=(const file_descriptor&) = delete;
- file_descriptor& operator=(file_descriptor&& other)
- {
- _cleanup();
- std::swap(_raw_fd, other._raw_fd);
- return *this;
- }
- file_descriptor(file_descriptor&& other) noexcept
- {
- std::swap(_raw_fd, other._raw_fd);
- }
+ file_descriptor(file_descriptor&& other) noexcept;
- ~file_descriptor()
- {
- _cleanup();
- }
+ file_descriptor& operator=(file_descriptor&& other) noexcept;
- int fd() const noexcept
- {
- LTTNG_ASSERT(_is_valid_fd(_raw_fd));
- return _raw_fd;
- }
+ ~file_descriptor() noexcept;
-private:
- static bool _is_valid_fd(int fd)
- {
- return fd >= 0;
- }
-
- void _cleanup()
- {
- if (!_is_valid_fd(_raw_fd)) {
- return;
- }
+ /*
+ * Read `size` bytes from the underlying file descriptor, assuming
+ * raw_fd behaves as a blocking device.
+ *
+ * Throws an exception if the requested amount of bytes couldn't be read.
+ */
+ void read(void *buffer, std::size_t size);
+ /*
+ * Write `size` bytes to the underlying file descriptor, assuming
+ * raw_fd behaves as a blocking device.
+ *
+ * Throws an exception if the requested amount of bytes couldn't be written.
+ */
+ void write(const void *buffer, std::size_t size);
- const auto ret = ::close(_raw_fd);
-
- _raw_fd = -1;
- if (ret) {
- PERROR("Failed to close file descriptor: fd=%i", _raw_fd);
- }
- }
+protected:
+ int _fd() const noexcept;
+ void _cleanup() noexcept;
+private:
int _raw_fd = -1;
};
*
*/
+#include <common/error.hpp>
#include <common/file-descriptor.hpp>
#include <common/format.hpp>
#include <common/hashtable/utils.hpp>
}() };
lttng::random::seed_t seed;
- const auto read_ret = lttng_read(urandom.fd(), &seed, sizeof(seed));
- if (read_ret != sizeof(seed)) {
- LTTNG_THROW_POSIX(fmt::format("Failed to read from `/dev/urandom`: size={}",
- sizeof(seed)),
- errno);
+ try {
+ urandom.read(&seed, sizeof(seed));
+ } catch (const std::exception& e) {
+ LTTNG_THROW_RANDOM_PRODUCTION_ERROR(fmt::format(
+ "Failed to read from `/dev/urandom`: size={}: {}", sizeof(seed), e.what()));
}
return seed;