[libcamera-devel] [PATCH 03/10] libcamera: Introduce Fence class
Jacopo Mondi
jacopo at jmondi.org
Thu Oct 28 13:15:13 CEST 2021
Fences are a synchronization mechanism that allows to receive event
notifications of a file descriptor with an optional expiration timeout.
Introduce the Fence class to model such a mechanism in libcamera.
Signed-off-by: Jacopo Mondi <jacopo at jmondi.org>
---
include/libcamera/internal/fence.h | 64 +++++++++
include/libcamera/internal/meson.build | 1 +
src/libcamera/fence.cpp | 185 +++++++++++++++++++++++++
src/libcamera/meson.build | 1 +
4 files changed, 251 insertions(+)
create mode 100644 include/libcamera/internal/fence.h
create mode 100644 src/libcamera/fence.cpp
diff --git a/include/libcamera/internal/fence.h b/include/libcamera/internal/fence.h
new file mode 100644
index 000000000000..5a78e0f864c7
--- /dev/null
+++ b/include/libcamera/internal/fence.h
@@ -0,0 +1,64 @@
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+/*
+ * Copyright (C) 2021, Google Inc.
+ *
+ * internal/fence.h - Synchronization fence
+ */
+#ifndef __LIBCAMERA_INTERNAL_FENCE_H__
+#define __LIBCAMERA_INTERNAL_FENCE_H__
+
+#include <mutex>
+
+#include <libcamera/base/class.h>
+#include <libcamera/base/event_notifier.h>
+#include <libcamera/base/timer.h>
+#include <libcamera/file_descriptor.h>
+
+namespace libcamera {
+
+class Fence
+{
+public:
+ explicit Fence(int fenceFd, unsigned int timeoutMs = kFenceTimeout);
+ Fence(Fence &&other);
+
+ Fence &operator=(Fence &&other);
+
+ int fd() const { return fd_.fd(); }
+
+ unsigned int timeout() const { return timeout_; }
+ bool completed() const { return completed_; }
+ bool expired() const { return expired_; }
+
+ void enable();
+ void disable();
+
+ Signal<> complete;
+
+private:
+ LIBCAMERA_DISABLE_COPY(Fence)
+
+ /* 300 milliseconds default timeout. */
+ static constexpr unsigned int kFenceTimeout = 300;
+
+ void moveFence(Fence &other);
+
+ void activated();
+ void timedout();
+
+ FileDescriptor fd_;
+ EventNotifier notifier_;
+
+ Timer timer_;
+ unsigned int timeout_;
+
+ bool completed_ = false;
+ bool expired_ = false;
+
+ std::mutex mutex_;
+};
+
+} /* namespace libcamera */
+
+#endif /* __LIBCAMERA_INTERNAL_FENCE_H__ */
+
diff --git a/include/libcamera/internal/meson.build b/include/libcamera/internal/meson.build
index cae65b0604ff..32d5c3387de3 100644
--- a/include/libcamera/internal/meson.build
+++ b/include/libcamera/internal/meson.build
@@ -22,6 +22,7 @@ libcamera_internal_headers = files([
'device_enumerator.h',
'device_enumerator_sysfs.h',
'device_enumerator_udev.h',
+ 'fence.h',
'formats.h',
'framebuffer.h',
'ipa_manager.h',
diff --git a/src/libcamera/fence.cpp b/src/libcamera/fence.cpp
new file mode 100644
index 000000000000..8fadb2c21f03
--- /dev/null
+++ b/src/libcamera/fence.cpp
@@ -0,0 +1,185 @@
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+/*
+ * Copyright (C) 2021, Google Inc.
+ *
+ * fence.cpp - Synchronization fence
+ */
+
+#include <libcamera/base/log.h>
+#include <libcamera/base/thread.h>
+#include <libcamera/internal/fence.h>
+
+namespace libcamera {
+
+/**
+ * \file internal/fence.h
+ * \brief Synchronization fence
+ */
+
+/**
+ * \class Fence
+ * \brief Synchronization fence class
+ *
+ * A Fence is a synchronization mechanism that allows to wait for a read event
+ * to happen on a file descriptor before an optional timeout expires.
+ *
+ * A Fence is created with a default timeout of 300 milliseconds, which can
+ * be overridden through the 'timeout' constructor parameter. Passing a 0
+ * timeout to the constructor disables timeouts completely.
+ *
+ * A Fence wraps a FileDescriptor and implements a move-only semantic, as Fence
+ * instances cannot be copied but only moved, causing the moved Fence to be
+ * reset by invalidating the wrapped FileDescriptor by disabling its
+ * notification and timeout mechanisms.
+ *
+ * When a read event is notified, the Fence is said to be 'completed',
+ * alternatively if the timeout expires before any event is notified the Fence
+ * is said to be 'expired'.
+ *
+ * In both cases, when an event notification happens or a timeout expires, the
+ * class emits the 'complete' signal, to which users of the class can connect
+ * to and check if the Fence has completed or has expired by calling the
+ * completed() and expired() functions.
+ *
+ * Fence instances are non-active by default (ie no events or timeout are
+ * generated) and need to be enabled by calling the enable() function. Likewise
+ * a Fence can be disabled by calling the disable() function.
+ *
+ * After a Fence has expired no events are generated and the Fence need to be
+ * manually re-enabled. Likewise, if the Fence is signalled the expiration
+ * timeout is cancelled.
+ */
+
+/**
+ * \brief Create a synchronization fence
+ * \param[in] fenceFd The synchronization fence file descriptor
+ * \param[in] timeoutMs The optional fence timeout. Set to 0 to disable timeout
+ */
+Fence::Fence(int fenceFd, unsigned int timeoutMs)
+ : fd_(std::move(fenceFd)),
+ notifier_(fd_.fd(), EventNotifier::Read, nullptr, false),
+ timeout_(timeoutMs)
+{
+ notifier_.activated.connect(this, &Fence::activated);
+
+ timer_.timeout.connect(this, &Fence::timedout);
+}
+
+void Fence::moveFence(Fence &other)
+{
+ fd_ = std::move(other.fd_);
+
+ other.disable();
+ if (other.timer_.isRunning())
+ other.timer_.stop();
+ other.timeout_ = 0;
+}
+
+/**
+ * \brief Move-construct a Fence
+ * \param[in] other The other fence to move
+ */
+Fence::Fence(Fence &&other)
+ : notifier_(other.fd(), EventNotifier::Read, nullptr, false)
+{
+ moveFence(other);
+
+ notifier_.activated.connect(this, &Fence::activated);
+ timer_.timeout.connect(this, &Fence::timedout);
+}
+
+/**
+ * \brief Move-assign the value of the \a other fence to this
+ * \param[in] other The other fence to move
+ * \return This fence
+ */
+Fence &Fence::operator=(Fence &&other)
+{
+ moveFence(other);
+
+ notifier_ = EventNotifier(fd_.fd(), EventNotifier::Read, nullptr, false);
+
+ return *this;
+}
+
+/**
+ * \fn Fence::fd() const
+ * \brief Return the synchronization fence file descriptor
+ * \return The synchronization fence file descriptor
+ */
+
+/**
+ * \fn Fence::timeout()
+ * \brief Retrieve the fence timeout
+ * \return The fence timeout in milliseconds
+ */
+
+/**
+ * \fn Fence::completed()
+ * \brief Check if the fence has completed before timing out
+ * \return True if the fence has completed
+ */
+
+/**
+ * \fn Fence::expired()
+ * \brief Check if the fence has expired before completing
+ * \return True if the fence has expired
+ */
+
+/**
+ * \brief Enable a fence by enabling events notifications
+ */
+void Fence::enable()
+{
+ MutexLocker lock(mutex_);
+
+ expired_ = false;
+ completed_ = false;
+
+ notifier_.setEnabled(true);
+ if (timeout_)
+ timer_.start(timeout_);
+}
+
+/**
+ * \brief Disable a fence by disabling events notifications
+ */
+void Fence::disable()
+{
+ notifier_.setEnabled(false);
+}
+
+/**
+ * \var Fence::complete
+ * \brief The fence completion signal
+ *
+ * A Fence is completed if signalled or timeout.
+ */
+
+void Fence::activated()
+{
+ MutexLocker lock(mutex_);
+
+ if (timer_.isRunning())
+ timer_.stop();
+
+ completed_ = true;
+ expired_ = false;
+
+ complete.emit();
+}
+
+void Fence::timedout()
+{
+ MutexLocker lock(mutex_);
+
+ expired_ = true;
+ completed_ = false;
+
+ /* Disable events notification after timeout. */
+ disable();
+
+ complete.emit();
+}
+
+} /* namespace libcamera */
diff --git a/src/libcamera/meson.build b/src/libcamera/meson.build
index 6727a777d804..6fb0d5f49b63 100644
--- a/src/libcamera/meson.build
+++ b/src/libcamera/meson.build
@@ -14,6 +14,7 @@ libcamera_sources = files([
'delayed_controls.cpp',
'device_enumerator.cpp',
'device_enumerator_sysfs.cpp',
+ 'fence.cpp',
'file_descriptor.cpp',
'formats.cpp',
'framebuffer.cpp',
--
2.33.1
More information about the libcamera-devel
mailing list