From patchwork Thu Oct 28 11:15:13 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jacopo Mondi X-Patchwork-Id: 14398 Return-Path: X-Original-To: parsemail@patchwork.libcamera.org Delivered-To: parsemail@patchwork.libcamera.org Received: from lancelot.ideasonboard.com (lancelot.ideasonboard.com [92.243.16.209]) by patchwork.libcamera.org (Postfix) with ESMTPS id C3C6EBF415 for ; Thu, 28 Oct 2021 11:14:46 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 81BFD60253; Thu, 28 Oct 2021 13:14:46 +0200 (CEST) Received: from relay9-d.mail.gandi.net (relay9-d.mail.gandi.net [217.70.183.199]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 27C5A600C2 for ; Thu, 28 Oct 2021 13:14:38 +0200 (CEST) Received: (Authenticated sender: jacopo@jmondi.org) by relay9-d.mail.gandi.net (Postfix) with ESMTPSA id 5499DFF802; Thu, 28 Oct 2021 11:14:38 +0000 (UTC) From: Jacopo Mondi To: libcamera-devel@lists.libcamera.org Date: Thu, 28 Oct 2021 13:15:13 +0200 Message-Id: <20211028111520.256612-4-jacopo@jmondi.org> X-Mailer: git-send-email 2.33.1 In-Reply-To: <20211028111520.256612-1-jacopo@jmondi.org> References: <20211028111520.256612-1-jacopo@jmondi.org> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH 03/10] libcamera: Introduce Fence class X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: libcamera-devel-bounces@lists.libcamera.org Sender: "libcamera-devel" 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 --- 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 + +#include +#include +#include +#include + +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 +#include +#include + +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',