[1/1] libcamera: Add mailbox template helper
diff mbox series

Message ID 20241001081824.960009-2-chenghaoyang@google.com
State New
Headers show
Series
  • Add MailBox
Related show

Commit Message

Harvey Yang Oct. 1, 2024, 8:10 a.m. UTC
From: Han-Lin Chen <hanlinchen@chromium.org>

MailBox is designed to be used to shares data, usually a frame buffer, among
tasks. A Mailbox can store a data which the producer task should set into,
and multiple consumer tasks could read the data from it. The data could
be set only once, i.e., there should be only one producer. All tasks shares
the Mailbox with share_ptr and the data it contains should be recycled when
all tasks are finished.

Signed-off-by: Hanlin Chen <hanlinchen@google.com>
Co-developed-by: Harvey Yang <chenghaoyang@chromium.org>
---
 include/libcamera/internal/mailbox.h   | 50 +++++++++++++
 include/libcamera/internal/meson.build |  1 +
 src/libcamera/mailbox.cpp              | 97 ++++++++++++++++++++++++++
 src/libcamera/meson.build              |  1 +
 4 files changed, 149 insertions(+)
 create mode 100644 include/libcamera/internal/mailbox.h
 create mode 100644 src/libcamera/mailbox.cpp

Comments

Barnabás Pőcze Oct. 1, 2024, 6:34 p.m. UTC | #1
Hi


2024. október 1., kedd 10:10 keltezéssel, Harvey Yang <chenghaoyang@chromium.org> írta:

> From: Han-Lin Chen <hanlinchen@chromium.org>
> 
> MailBox is designed to be used to shares data, usually a frame buffer, among
                                         ^
                                    share

> tasks. A Mailbox can store a data which the producer task should set into,
               ^
           MailBox

> and multiple consumer tasks could read the data from it. The data could
> be set only once, i.e., there should be only one producer. All tasks shares
                                                                            ^
                                                                       share

> the Mailbox with share_ptr and the data it contains should be recycled when
          ^            ^
      MailBox      shared_ptr

> all tasks are finished.
> 
> Signed-off-by: Hanlin Chen <hanlinchen@google.com>
> Co-developed-by: Harvey Yang <chenghaoyang@chromium.org>
> ---
>  include/libcamera/internal/mailbox.h   | 50 +++++++++++++
>  include/libcamera/internal/meson.build |  1 +
>  src/libcamera/mailbox.cpp              | 97 ++++++++++++++++++++++++++
>  src/libcamera/meson.build              |  1 +
>  4 files changed, 149 insertions(+)
>  create mode 100644 include/libcamera/internal/mailbox.h
>  create mode 100644 src/libcamera/mailbox.cpp
> 
> diff --git a/include/libcamera/internal/mailbox.h b/include/libcamera/internal/mailbox.h
> new file mode 100644
> index 00000000..fb27f5bb
> --- /dev/null
> +++ b/include/libcamera/internal/mailbox.h
> @@ -0,0 +1,50 @@
> +/* SPDX-License-Identifier: LGPL-2.1-or-later */
> +/*
> + * Copyright (C) 2024, Google Inc.
> + *
> + * mailbox.h - Template class for generic mailbox
> + */
> +
> +#pragma once
> +
> +#include <functional>
> +#include <memory>
> +#include <vector>
> +
> +namespace libcamera {
> +
> +template<class T>
> +class MailBox
> +{
> +public:
> +	using Recycler = std::function<void(T &)>;
> +
> +	MailBox()
> +		: valid_(false) {}
> +	~MailBox();
> +
> +	void put(const T &item, Recycler recycler);
> +
> +	const T &get();
> +
> +	bool valid() { return valid_; }
> +
> +private:
> +	T item_;
> +	bool valid_;
> +	std::function<void(T &)> recycler_;
> +};
> +
> +template<class T>
> +using SharedMailBox = std::shared_ptr<MailBox<T>>;
> +
> +template<class T>
> +SharedMailBox<T> makeMailBox()
> +{
> +	return std::make_shared<MailBox<T>>();
> +}
> +
> +template<class T>
> +std::vector<SharedMailBox<T>> makeMailBoxVector(const unsigned int count);

You have to put the definitions of templates in the header file, otherwise it won't work.

Also, this whole concept looks to me to be very similar to a `const std::shared_ptr<T>`
with a custom deleter (with the difference that you can only obtain a `const` reference
here unlike with an `std::shared_ptr`). So I am wondering if utilizing `std::shared_ptr`
with a custom deleter has been explored already.

I am also wondering if it wouldn't make more sense to remove `MailBox::put()`
and just have the two constructors taking `const T&` and `T&&`, and initializing
`item_`. This would do away with the need for the `valid_` member. Is there a
planned use case where that is not sufficient?


Regards,
Barnabás Pőcze


> +
> +} /* namespace libcamera */
> [...]

Patch
diff mbox series

diff --git a/include/libcamera/internal/mailbox.h b/include/libcamera/internal/mailbox.h
new file mode 100644
index 00000000..fb27f5bb
--- /dev/null
+++ b/include/libcamera/internal/mailbox.h
@@ -0,0 +1,50 @@ 
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+/*
+ * Copyright (C) 2024, Google Inc.
+ *
+ * mailbox.h - Template class for generic mailbox
+ */
+
+#pragma once
+
+#include <functional>
+#include <memory>
+#include <vector>
+
+namespace libcamera {
+
+template<class T>
+class MailBox
+{
+public:
+	using Recycler = std::function<void(T &)>;
+
+	MailBox()
+		: valid_(false) {}
+	~MailBox();
+
+	void put(const T &item, Recycler recycler);
+
+	const T &get();
+
+	bool valid() { return valid_; }
+
+private:
+	T item_;
+	bool valid_;
+	std::function<void(T &)> recycler_;
+};
+
+template<class T>
+using SharedMailBox = std::shared_ptr<MailBox<T>>;
+
+template<class T>
+SharedMailBox<T> makeMailBox()
+{
+	return std::make_shared<MailBox<T>>();
+}
+
+template<class T>
+std::vector<SharedMailBox<T>> makeMailBoxVector(const unsigned int count);
+
+} /* namespace libcamera */
diff --git a/include/libcamera/internal/meson.build b/include/libcamera/internal/meson.build
index 1c5eef9c..4c1228b9 100644
--- a/include/libcamera/internal/meson.build
+++ b/include/libcamera/internal/meson.build
@@ -27,6 +27,7 @@  libcamera_internal_headers = files([
     'ipa_proxy.h',
     'ipc_pipe.h',
     'ipc_unixsocket.h',
+    'mailbox.h',
     'mapped_framebuffer.h',
     'media_device.h',
     'media_object.h',
diff --git a/src/libcamera/mailbox.cpp b/src/libcamera/mailbox.cpp
new file mode 100644
index 00000000..4d129224
--- /dev/null
+++ b/src/libcamera/mailbox.cpp
@@ -0,0 +1,97 @@ 
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+/*
+ * Copyright (C) 2024, Google Inc.
+ *
+ * mailbox.cpp - Template class for generic mailbox
+ */
+
+#include "libcamera/internal/mailbox.h"
+
+#include <libcamera/base/log.h>
+
+namespace libcamera {
+
+/**
+ * \class MailBox
+ * \brief MailBox of data
+ *
+ * A MailBox contains a block of data that has a single producer, and one or
+ * multiple consumers. It's often used as a shared_ptr (SharedMailBox) and
+ * being held by different tasks in pipelines.
+ */
+
+/**
+ * \typedef MailBox::Recycler
+ * \brief A function that recycles the data when the mailbox is destructed
+ */
+
+template<class T>
+MailBox<T>::~MailBox()
+{
+	if (valid_ && recycler_)
+		recycler_(item_);
+}
+
+/**
+ * \brief Set the data as the producer. Should be called only once
+ * \param[in] item The data to be stored
+ * \param[in] recycler The function that recycles \a data when destructing the
+ * mailbox. Mostly used for recycling buffers.
+ */
+template<class T>
+void MailBox<T>::put(const T &item, MailBox<T>::Recycler recycler)
+{
+	ASSERT(!valid_);
+
+	valid_ = true;
+	recycler_ = recycler;
+	item_ = item;
+}
+
+/**
+ * \brief Get the data as a consumer. put() function should be called ahead
+ *
+ * \return The stored data
+ */
+template<class T>
+const T &MailBox<T>::get()
+{
+	ASSERT(valid_);
+	return item_;
+}
+
+/**
+ * \fn MailBox::valid()
+ * \return True if put() function has been called
+ */
+
+/**
+ * \typedef SharedMailBox
+ * \brief A mailbox as a shared_ptr
+ */
+
+/**
+ * \fn makeMailBox()
+ * \brief A helper function to create a SharedMailBox
+ *
+ * \return A mailbox as a SharedMailBox
+ */
+
+/**
+ * \brief A helper function to create a list of mailboxes
+ * \param[in] count The number of mailboxes requested
+ *
+ * \return Mailboxes as a vector
+ */
+template<class T>
+std::vector<SharedMailBox<T>> makeMailBoxVector(const unsigned int count)
+{
+	std::vector<SharedMailBox<T>> mailBoxes;
+	mailBoxes.resize(count);
+	for (unsigned int i = 0; i < count; i++)
+		mailBoxes[i] = makeMailBox<T>();
+
+	return mailBoxes;
+}
+
+} /* namespace libcamera */
diff --git a/src/libcamera/meson.build b/src/libcamera/meson.build
index aa9ab029..6c3ef537 100644
--- a/src/libcamera/meson.build
+++ b/src/libcamera/meson.build
@@ -38,6 +38,7 @@  libcamera_internal_sources = files([
     'ipc_pipe.cpp',
     'ipc_pipe_unixsocket.cpp',
     'ipc_unixsocket.cpp',
+    'mailbox.cpp',
     'mapped_framebuffer.cpp',
     'media_device.cpp',
     'media_object.cpp',