summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/libcamera/internal/control_serializer.h8
-rw-r--r--src/libcamera/control_serializer.cpp63
-rw-r--r--test/serialization/control_serialization.cpp4
-rw-r--r--test/serialization/ipa_data_serializer_test.cpp6
-rw-r--r--utils/ipc/generators/libcamera_templates/module_ipa_proxy.cpp.tmpl3
-rw-r--r--utils/ipc/generators/libcamera_templates/module_ipa_proxy_worker.cpp.tmpl4
6 files changed, 75 insertions, 13 deletions
diff --git a/include/libcamera/internal/control_serializer.h b/include/libcamera/internal/control_serializer.h
index 8a66be32..caeafa11 100644
--- a/include/libcamera/internal/control_serializer.h
+++ b/include/libcamera/internal/control_serializer.h
@@ -20,7 +20,12 @@ class ByteStreamBuffer;
class ControlSerializer
{
public:
- ControlSerializer();
+ enum class Role {
+ Proxy,
+ Worker
+ };
+
+ ControlSerializer(Role role);
void reset();
@@ -47,6 +52,7 @@ private:
ControlInfo loadControlInfo(ControlType type, ByteStreamBuffer &buffer);
unsigned int serial_;
+ unsigned int serialSeed_;
std::vector<std::unique_ptr<ControlId>> controlIds_;
std::vector<std::unique_ptr<ControlIdMap>> controlIdMaps_;
std::map<unsigned int, ControlInfoMap> infoMaps_;
diff --git a/src/libcamera/control_serializer.cpp b/src/libcamera/control_serializer.cpp
index e1ba6d14..77b77448 100644
--- a/src/libcamera/control_serializer.cpp
+++ b/src/libcamera/control_serializer.cpp
@@ -62,6 +62,14 @@ LOG_DEFINE_CATEGORY(Serializer)
* corresponding ControlInfoMap handle in the binary data, and when
* deserializing to retrieve the corresponding ControlInfoMap.
*
+ * As independent ControlSerializer instances are used on both sides of the IPC
+ * boundary, and the two instances operate without a shared point of control,
+ * there is a potential risk of collision of the numerical handles assigned to
+ * each serialized ControlInfoMap. For this reason the control serializer is
+ * initialized with a seed and the handle is incremented by 2, so that instances
+ * initialized with a different seed operate on a separate numerical space,
+ * avoiding any collision risk.
+ *
* In order to perform those tasks, the serializer keeps an internal state that
* needs to be properly populated. This mechanism requires the ControlInfoMap
* corresponding to a ControlList to have been serialized or deserialized
@@ -77,9 +85,45 @@ LOG_DEFINE_CATEGORY(Serializer)
* proceed with care to avoid stale references.
*/
-ControlSerializer::ControlSerializer()
- : serial_(0)
+/**
+ * \enum ControlSerializer::Role
+ * \brief Define the role of the IPC component using the control serializer
+ *
+ * The role of the component that creates the serializer is used to initialize
+ * the handles numerical space.
+ *
+ * \var ControlSerializer::Role::Proxy
+ * \brief The control serializer is used by the IPC Proxy classes
+ *
+ * \var ControlSerializer::Role::Worker
+ * \brief The control serializer is used by the IPC ProxyWorker classes
+ */
+
+/**
+ * \brief Construct a new ControlSerializer
+ * \param[in] role The role of the IPC component using the serializer
+ */
+ControlSerializer::ControlSerializer(Role role)
{
+ /*
+ * Initialize the handle numerical space using the role of the
+ * component that created the instance.
+ *
+ * Instances initialized for a different role will use a different
+ * numerical handle space, avoiding any collision risk when, in example,
+ * two instances of the ControlSerializer class are used at the IPC
+ * boundaries.
+ *
+ * Start counting handles from '1' as '0' is a special value used as
+ * place holder when serializing lists that do not have a ControlInfoMap
+ * associated (in example list of libcamera controls::controls).
+ *
+ * \todo This is a temporary hack and should probably be better
+ * engineered, but for the time being it avoids collisions on the handle
+ * value when using IPC.
+ */
+ serialSeed_ = role == Role::Proxy ? 1 : 2;
+ serial_ = serialSeed_;
}
/**
@@ -90,7 +134,7 @@ ControlSerializer::ControlSerializer()
*/
void ControlSerializer::reset()
{
- serial_ = 0;
+ serial_ = serialSeed_;
infoMapHandles_.clear();
infoMaps_.clear();
@@ -200,10 +244,10 @@ int ControlSerializer::serialize(const ControlInfoMap &infoMap,
else
idMapType = IPA_CONTROL_ID_MAP_V4L2;
- /* Prepare the packet header, assign a handle to the ControlInfoMap. */
+ /* Prepare the packet header. */
struct ipa_controls_header hdr;
hdr.version = IPA_CONTROLS_FORMAT_VERSION;
- hdr.handle = ++serial_;
+ hdr.handle = serial_;
hdr.entries = infoMap.size();
hdr.size = sizeof(hdr) + entriesSize + valuesSize;
hdr.data_offset = sizeof(hdr) + entriesSize;
@@ -212,6 +256,15 @@ int ControlSerializer::serialize(const ControlInfoMap &infoMap,
buffer.write(&hdr);
/*
+ * Increment the handle for the ControlInfoMap by 2 to keep the handles
+ * numerical space partitioned between instances initialized for a
+ * different role.
+ *
+ * \sa ControlSerializer::Role
+ */
+ serial_ += 2;
+
+ /*
* Serialize all entries.
* \todo Serialize the control name too
*/
diff --git a/test/serialization/control_serialization.cpp b/test/serialization/control_serialization.cpp
index 5ac9c4ed..a507d98a 100644
--- a/test/serialization/control_serialization.cpp
+++ b/test/serialization/control_serialization.cpp
@@ -30,8 +30,8 @@ protected:
int run() override
{
- ControlSerializer serializer;
- ControlSerializer deserializer;
+ ControlSerializer serializer(ControlSerializer::Role::Proxy);
+ ControlSerializer deserializer(ControlSerializer::Role::Worker);
std::vector<uint8_t> infoData;
std::vector<uint8_t> listData;
diff --git a/test/serialization/ipa_data_serializer_test.cpp b/test/serialization/ipa_data_serializer_test.cpp
index eca19a66..5fcdcb8e 100644
--- a/test/serialization/ipa_data_serializer_test.cpp
+++ b/test/serialization/ipa_data_serializer_test.cpp
@@ -162,7 +162,7 @@ private:
int testControls()
{
- ControlSerializer cs;
+ ControlSerializer cs(ControlSerializer::Role::Proxy);
const ControlInfoMap &infoMap = camera_->controls();
ControlList list = generateControlList(infoMap);
@@ -195,7 +195,7 @@ private:
int testVector()
{
- ControlSerializer cs;
+ ControlSerializer cs(ControlSerializer::Role::Proxy);
/*
* We don't test FileDescriptor serdes because it dup()s, so we
@@ -265,7 +265,7 @@ private:
int testMap()
{
- ControlSerializer cs;
+ ControlSerializer cs(ControlSerializer::Role::Proxy);
/*
* Realistically, only string and integral keys.
diff --git a/utils/ipc/generators/libcamera_templates/module_ipa_proxy.cpp.tmpl b/utils/ipc/generators/libcamera_templates/module_ipa_proxy.cpp.tmpl
index aab1fffb..d856339a 100644
--- a/utils/ipc/generators/libcamera_templates/module_ipa_proxy.cpp.tmpl
+++ b/utils/ipc/generators/libcamera_templates/module_ipa_proxy.cpp.tmpl
@@ -46,7 +46,8 @@ namespace {{ns}} {
{%- endif %}
{{proxy_name}}::{{proxy_name}}(IPAModule *ipam, bool isolate)
- : IPAProxy(ipam), isolate_(isolate), seq_(0)
+ : IPAProxy(ipam), isolate_(isolate),
+ controlSerializer_(ControlSerializer::Role::Proxy), seq_(0)
{
LOG(IPAProxy, Debug)
<< "initializing {{module_name}} proxy: loading IPA from "
diff --git a/utils/ipc/generators/libcamera_templates/module_ipa_proxy_worker.cpp.tmpl b/utils/ipc/generators/libcamera_templates/module_ipa_proxy_worker.cpp.tmpl
index 890246a8..764e7a3a 100644
--- a/utils/ipc/generators/libcamera_templates/module_ipa_proxy_worker.cpp.tmpl
+++ b/utils/ipc/generators/libcamera_templates/module_ipa_proxy_worker.cpp.tmpl
@@ -53,7 +53,9 @@ class {{proxy_worker_name}}
{
public:
{{proxy_worker_name}}()
- : ipa_(nullptr), exit_(false) {}
+ : ipa_(nullptr),
+ controlSerializer_(ControlSerializer::Role::Worker),
+ exit_(false) {}
~{{proxy_worker_name}}() {}