[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