Many signals used in internal and public APIs carry the emitter pointer as a signal argument. This was done to allow slots connected to multiple signal instances to differentiate between emitters. While starting from a good intention of facilitating the implementation of slots, it turned out to be a bad API design as the signal isn't meant to know what it will be connected to, and thus shouldn't carry parameters that are solely meant to support a use case specific to the connected slot. These pointers turn out to be unused in all slots but one. In the only case where it is needed, it can be obtained by wrapping the slot in a lambda function when connecting the signal. Do so, and drop the emitter pointer from all signals. Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com> Reviewed-by: Umang Jain <umang.jain@ideasonboard.com>
146 lines
3.2 KiB
C++
146 lines
3.2 KiB
C++
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
|
/*
|
|
* Copyright (C) 2020, Google Inc.
|
|
*
|
|
* ipc_pipe_unixsocket.cpp - Image Processing Algorithm IPC module using unix socket
|
|
*/
|
|
|
|
#include "libcamera/internal/ipc_pipe_unixsocket.h"
|
|
|
|
#include <vector>
|
|
|
|
#include <libcamera/base/event_dispatcher.h>
|
|
#include <libcamera/base/log.h>
|
|
#include <libcamera/base/thread.h>
|
|
#include <libcamera/base/timer.h>
|
|
|
|
#include "libcamera/internal/ipc_pipe.h"
|
|
#include "libcamera/internal/ipc_unixsocket.h"
|
|
#include "libcamera/internal/process.h"
|
|
|
|
namespace libcamera {
|
|
|
|
LOG_DECLARE_CATEGORY(IPCPipe)
|
|
|
|
IPCPipeUnixSocket::IPCPipeUnixSocket(const char *ipaModulePath,
|
|
const char *ipaProxyWorkerPath)
|
|
: IPCPipe()
|
|
{
|
|
std::vector<int> fds;
|
|
std::vector<std::string> args;
|
|
args.push_back(ipaModulePath);
|
|
|
|
socket_ = std::make_unique<IPCUnixSocket>();
|
|
int fd = socket_->create();
|
|
if (fd < 0) {
|
|
LOG(IPCPipe, Error) << "Failed to create socket";
|
|
return;
|
|
}
|
|
socket_->readyRead.connect(this, &IPCPipeUnixSocket::readyRead);
|
|
args.push_back(std::to_string(fd));
|
|
fds.push_back(fd);
|
|
|
|
proc_ = std::make_unique<Process>();
|
|
int ret = proc_->start(ipaProxyWorkerPath, args, fds);
|
|
if (ret) {
|
|
LOG(IPCPipe, Error)
|
|
<< "Failed to start proxy worker process";
|
|
return;
|
|
}
|
|
|
|
connected_ = true;
|
|
}
|
|
|
|
IPCPipeUnixSocket::~IPCPipeUnixSocket()
|
|
{
|
|
}
|
|
|
|
int IPCPipeUnixSocket::sendSync(const IPCMessage &in, IPCMessage *out)
|
|
{
|
|
IPCUnixSocket::Payload response;
|
|
|
|
int ret = call(in.payload(), &response, in.header().cookie);
|
|
if (ret) {
|
|
LOG(IPCPipe, Error) << "Failed to call sync";
|
|
return ret;
|
|
}
|
|
|
|
if (out)
|
|
*out = IPCMessage(response);
|
|
|
|
return 0;
|
|
}
|
|
|
|
int IPCPipeUnixSocket::sendAsync(const IPCMessage &data)
|
|
{
|
|
int ret = socket_->send(data.payload());
|
|
if (ret) {
|
|
LOG(IPCPipe, Error) << "Failed to call async";
|
|
return ret;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
void IPCPipeUnixSocket::readyRead()
|
|
{
|
|
IPCUnixSocket::Payload payload;
|
|
int ret = socket_->receive(&payload);
|
|
if (ret) {
|
|
LOG(IPCPipe, Error) << "Receive message failed" << ret;
|
|
return;
|
|
}
|
|
|
|
/* \todo Use span to avoid the double copy when callData is found. */
|
|
if (payload.data.size() < sizeof(IPCMessage::Header)) {
|
|
LOG(IPCPipe, Error) << "Not enough data received";
|
|
return;
|
|
}
|
|
|
|
IPCMessage ipcMessage(payload);
|
|
|
|
auto callData = callData_.find(ipcMessage.header().cookie);
|
|
if (callData != callData_.end()) {
|
|
*callData->second.response = std::move(payload);
|
|
callData->second.done = true;
|
|
return;
|
|
}
|
|
|
|
/* Received unexpected data, this means it's a call from the IPA. */
|
|
recv.emit(ipcMessage);
|
|
}
|
|
|
|
int IPCPipeUnixSocket::call(const IPCUnixSocket::Payload &message,
|
|
IPCUnixSocket::Payload *response, uint32_t cookie)
|
|
{
|
|
Timer timeout;
|
|
int ret;
|
|
|
|
const auto result = callData_.insert({ cookie, { response, false } });
|
|
const auto &iter = result.first;
|
|
|
|
ret = socket_->send(message);
|
|
if (ret) {
|
|
callData_.erase(iter);
|
|
return ret;
|
|
}
|
|
|
|
/* \todo Make this less dangerous, see IPCPipe::sendSync() */
|
|
timeout.start(2000);
|
|
while (!iter->second.done) {
|
|
if (!timeout.isRunning()) {
|
|
LOG(IPCPipe, Error) << "Call timeout!";
|
|
callData_.erase(iter);
|
|
return -ETIMEDOUT;
|
|
}
|
|
|
|
Thread::current()->eventDispatcher()->processEvents();
|
|
}
|
|
|
|
callData_.erase(iter);
|
|
|
|
return 0;
|
|
}
|
|
|
|
} /* namespace libcamera */
|