From patchwork Sat Dec 5 10:30:49 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Paul Elder X-Patchwork-Id: 10569 X-Patchwork-Delegate: paul.elder@ideasonboard.com 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 01D95BDB20 for ; Sat, 5 Dec 2020 10:31:32 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id C5A8263603; Sat, 5 Dec 2020 11:31:31 +0100 (CET) Authentication-Results: lancelot.ideasonboard.com; dkim=fail reason="signature verification failed" (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="VtlYRW2m"; dkim-atps=neutral Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [213.167.242.64]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 9F58A635F4 for ; Sat, 5 Dec 2020 11:31:29 +0100 (CET) Received: from pyrite.rasen.tech (unknown [IPv6:2400:4051:61:600:2c71:1b79:d06d:5032]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id AA4112A4; Sat, 5 Dec 2020 11:31:27 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1607164289; bh=Qp4IsCKX1ywvnhlR45uHrqBOwRGuM3Li1dgErMeWwmY=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=VtlYRW2mN+ysLTOHjIVKYoBHfkxifyvQQPafQ/bd9cI7QylaDBOGUwhJSEr3zUPiT eJIz6iWNUKwRpTgCkpSr1Hpdap2ItxxDsOrTTf6/u+SXIX7kPV4IcFmNgG9mN4JsHR LfDjD8ABG3Lb+9+bBLGzx4/3kZs/MaY+agxhk7Os= From: Paul Elder To: libcamera-devel@lists.libcamera.org Date: Sat, 5 Dec 2020 19:30:49 +0900 Message-Id: <20201205103106.242080-7-paul.elder@ideasonboard.com> X-Mailer: git-send-email 2.27.0 In-Reply-To: <20201205103106.242080-1-paul.elder@ideasonboard.com> References: <20201205103106.242080-1-paul.elder@ideasonboard.com> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v5 06/23] libcamera: Add IPCPipe 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" Create a virtual IPCPipe class that models an IPC/RPC system. IPA proxies and proxy workers will call into the IPCPipe, rather than implementing the IPC themselves. Signed-off-by: Paul Elder Reviewed-by: Jacopo Mondi Reviewed-by: Niklas Söderlund --- Changes in v5: - fix style - rename ipa_ipc.[(cpp)h] to ipc_pipe.[(cpp),h] - rename IPAIPC to IPCPipe - add IPCMessage to use in the IPCPipe Change in v4: - change snake_case to camelCase - remove ipaModulePath and ipaProxyWorkerPath from parameters in the IPAIPC base contructor - include signal.h Changes in v3: - expand documentation a bit - move [[maybe_unused]] to after the parameters in the IPAIPC constructor, to appease gcc <= 9.1 Changes in v2: - add documentation --- .../libcamera/internal/ipa_data_serializer.h | 2 +- include/libcamera/internal/ipc_pipe.h | 70 ++++++ src/libcamera/ipc_pipe.cpp | 211 ++++++++++++++++++ src/libcamera/meson.build | 1 + 4 files changed, 283 insertions(+), 1 deletion(-) create mode 100644 include/libcamera/internal/ipc_pipe.h create mode 100644 src/libcamera/ipc_pipe.cpp diff --git a/include/libcamera/internal/ipa_data_serializer.h b/include/libcamera/internal/ipa_data_serializer.h index 0394ab3a..9d4aaba5 100644 --- a/include/libcamera/internal/ipa_data_serializer.h +++ b/include/libcamera/internal/ipa_data_serializer.h @@ -286,7 +286,7 @@ public: fdIter, fdIter + sizeofFds, cs); - ret.insert({key, value}); + ret.insert({ key, value }); dataIter += sizeofData; fdIter += sizeofFds; diff --git a/include/libcamera/internal/ipc_pipe.h b/include/libcamera/internal/ipc_pipe.h new file mode 100644 index 00000000..0232c3b5 --- /dev/null +++ b/include/libcamera/internal/ipc_pipe.h @@ -0,0 +1,70 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +/* + * Copyright (C) 2020, Google Inc. + * + * ipc_pipe.h - Image Processing Algorithm IPC module for IPA proxies + */ +#ifndef __LIBCAMERA_INTERNAL_IPA_IPC_H__ +#define __LIBCAMERA_INTERNAL_IPA_IPC_H__ + +#include + +#include "libcamera/internal/ipc_unixsocket.h" + +#include + +namespace libcamera { + +class IPCMessage +{ +public: + struct Header { + uint32_t cmd; + uint32_t cookie; + }; + + IPCMessage(); + IPCMessage(const Header &header); + IPCMessage(const IPCUnixSocket::Payload &payload); + + const IPCUnixSocket::Payload payload(const Header *header = nullptr) const; + + Header &header() { return header_; } + std::vector &data() { return data_; } + std::vector &fds() { return fds_; } + + const Header &cheader() const { return header_; } + const std::vector &cdata() const { return data_; } + const std::vector &cfds() const { return fds_; } + +private: + Header header_; + + std::vector data_; + std::vector fds_; +}; + +class IPCPipe +{ +public: + IPCPipe(); + virtual ~IPCPipe(); + + bool isConnected() const { return connected_; } + + virtual int sendSync(uint32_t cmd, + const IPCMessage &in, + IPCMessage *out) = 0; + + virtual int sendAsync(uint32_t cmd, + const IPCMessage &data) = 0; + + Signal recv; + +protected: + bool connected_; +}; + +} /* namespace libcamera */ + +#endif /* __LIBCAMERA_INTERNAL_IPA_IPC_H__ */ diff --git a/src/libcamera/ipc_pipe.cpp b/src/libcamera/ipc_pipe.cpp new file mode 100644 index 00000000..eb439724 --- /dev/null +++ b/src/libcamera/ipc_pipe.cpp @@ -0,0 +1,211 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +/* + * Copyright (C) 2020, Google Inc. + * + * ipc_pipe.cpp - Image Processing Algorithm IPC module for IPA proxies + */ + +#include "libcamera/internal/ipc_pipe.h" + +#include "libcamera/internal/log.h" + +/** + * \file ipc_pipe.h + * \brief IPC mechanism for IPA isolation + */ + +namespace libcamera { + +LOG_DEFINE_CATEGORY(IPCPipe) + +/** + * \struct IPCMessage::Header + * \brief Container for an IPCMessage header + * + * Holds a cmd code for the IPC message, and a cookie. + */ + +/** + * \var IPCMessage::Header::cmd + * \brief Type of IPCMessage + * + * Typically used to carry a command code for an RPC. + */ + +/** + * \var IPCMessage::Header::cookie + * \brief Cookie to idetify the message and a corresponding reply. + * + * Populated and used by IPCPipe implementations for matching calls with + * replies. + */ + +/** + * \class IPCMessage + * \brief IPC message to be passed through IPC message pipe + */ + +/** + * \brief Construct an IPCMessage instance + */ +IPCMessage::IPCMessage() + : header_(Header{ 0, 0 }) +{ +} + +/** + * \brief Construct an IPCMessage instance with a given header + * \param[in] header The header that the constructed IPCMessage will contain + */ +IPCMessage::IPCMessage(const Header &header) + : header_(header) +{ +} + +/** + * \brief Construct an IPCMessage instance from an IPC payload + * \param[in] payload The IPCUnixSocket payload to construct from + * + * This essentially converts an IPCUnixSocket payload into an IPCMessage. + * The header is extracted from the payload into the IPCMessage's header field. + */ +IPCMessage::IPCMessage(const IPCUnixSocket::Payload &payload) +{ + memcpy(&header_, &*payload.data.begin(), sizeof(header_)); + data_ = std::vector(payload.data.begin() + sizeof(header_), + payload.data.end()); + fds_ = std::vector(payload.fds.begin(), payload.fds.end()); +} + +/** + * \brief Create an IPCUnixSocket payload from the IPCMessage + * \param[in] header Header to use when constructing the payload, if applicable + * + * This essentially converts the IPCMessage into an IPCUnixSocket payload. If + * \a header is not provided (ie. nullptr), then the header field that is + * internal to the IPCMessage will be used. + */ +const IPCUnixSocket::Payload IPCMessage::payload(const Header *header) const +{ + IPCUnixSocket::Payload message; + + message.data.resize(sizeof(Header) + data_.size()); + message.fds.reserve(fds_.size()); + + memcpy(&*message.data.begin(), header ? header : &header_, sizeof(Header)); + + /* \todo Make this work without copy */ + memcpy(&*(message.data.begin() + sizeof(Header)), data_.data(), data_.size()); + message.fds = const_cast &>(fds_); + + return message; +} + +/** + * \fn IPCMessage::header() + * \brief Returns a reference to the header + */ + +/** + * \fn IPCMessage::data() + * \brief Returns a reference to the byte vector containing data + */ + +/** + * \fn IPCMessage::fds() + * \brief Returns a reference to the vector containing file descriptors + */ + +/** + * \fn IPCMessage::cheader() + * \brief Returns a const reference to the header + */ + +/** + * \fn IPCMessage::cdata() + * \brief Returns a const reference to the byte vector containing data + */ + +/** + * \fn IPCMessage::cfds() + * \brief Returns a const reference to the vector containing file descriptors + */ + +/** + * \class IPCPipe + * \brief IPC message pipe for IPA isolation + * + * Virtual class to model an IPC message pipe for use by IPA proxies for IPA + * isolation. sendSync() and sendAsync() must be implemented, and the recvMessage + * signal must be emitted whenever new data is available. + */ + +/** + * \brief Construct an IPCPipe instance + */ +IPCPipe::IPCPipe() + : connected_(false) +{ +} + +IPCPipe::~IPCPipe() +{ +} + +/** + * \fn IPCPipe::isConnected() + * \brief Check if the IPCPipe instance is connected + * + * An IPCPipe instance is connected if IPC is successfully set up. + * + * \return True if the IPCPipe is connected, false otherwise + */ + +/** + * \fn IPCPipe::sendSync() + * \brief Send a message over IPC synchronously + * \param[in] cmd Command ID + * \param[in] in Data to send, as an IPCMessage + * \param[in] out IPCMessage instance in which to receive data, if applicable + * + * This function will not return until a response is received. The event loop + * will still continue to execute, however. + * + * \return Zero on success, negative error code otherwise + */ + +/** + * \fn IPCPipe::sendAsync() + * \brief Send a message over IPC asynchronously + * \param[in] cmd Command ID + * \param[in] data Data to send, as an IPCMessage + * + * This function will return immediately after sending the message. + * + * \return Zero on success, negative error code otherwise + */ + +/** + * \var IPCPipe::recv + * \brief Signal to be emitted when data is received over IPC + * + * When data is received over IPC, this signal shall be emitted. Users must + * connect to this to receive new data. + * + * The parameters of the signal are a vector of bytes and a vector of file + * descriptors. + */ + +/** + * \var IPCPipe::connected_ + * \brief Flag to indicate if the IPCPipe instance is connected + * + * An IPCPipe instance is connected if IPC is successfully set up. + * + * This flag can be read via IPCPipe::isConnected(). + * + * Implementations of the IPCPipe class should set this flag upon successful + * construction. + */ + +} /* namespace libcamera */ diff --git a/src/libcamera/meson.build b/src/libcamera/meson.build index 1291f1b3..b7cfe0c2 100644 --- a/src/libcamera/meson.build +++ b/src/libcamera/meson.build @@ -30,6 +30,7 @@ libcamera_sources = files([ 'ipa_manager.cpp', 'ipa_module.cpp', 'ipa_proxy.cpp', + 'ipc_pipe.cpp', 'ipc_unixsocket.cpp', 'log.cpp', 'media_device.cpp',