diff options
Diffstat (limited to 'utils/codegen/ipc/generators/libcamera_templates/module_ipa_proxy_worker.cpp.tmpl')
-rw-r--r-- | utils/codegen/ipc/generators/libcamera_templates/module_ipa_proxy_worker.cpp.tmpl | 246 |
1 files changed, 246 insertions, 0 deletions
diff --git a/utils/codegen/ipc/generators/libcamera_templates/module_ipa_proxy_worker.cpp.tmpl b/utils/codegen/ipc/generators/libcamera_templates/module_ipa_proxy_worker.cpp.tmpl new file mode 100644 index 00000000..1f990d3f --- /dev/null +++ b/utils/codegen/ipc/generators/libcamera_templates/module_ipa_proxy_worker.cpp.tmpl @@ -0,0 +1,246 @@ +{#- + # SPDX-License-Identifier: LGPL-2.1-or-later + # Copyright (C) 2020, Google Inc. +-#} +{%- import "proxy_functions.tmpl" as proxy_funcs -%} + +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +/* + * Copyright (C) 2020, Google Inc. + * + * Image Processing Algorithm proxy worker for {{module_name}} + * + * This file is auto-generated. Do not edit. + */ + +{#- \todo Split proxy worker into IPC worker and proxy worker. #} + +#include <algorithm> +#include <iostream> +#include <sys/types.h> +#include <tuple> +#include <unistd.h> + +#include <libcamera/ipa/ipa_interface.h> +#include <libcamera/ipa/{{module_name}}_ipa_interface.h> +#include <libcamera/ipa/{{module_name}}_ipa_serializer.h> +#include <libcamera/logging.h> + +#include <libcamera/base/event_dispatcher.h> +#include <libcamera/base/log.h> +#include <libcamera/base/thread.h> +#include <libcamera/base/unique_fd.h> + +#include "libcamera/internal/camera_sensor.h" +#include "libcamera/internal/control_serializer.h" +#include "libcamera/internal/ipa_data_serializer.h" +#include "libcamera/internal/ipa_module.h" +#include "libcamera/internal/ipa_proxy.h" +#include "libcamera/internal/ipc_pipe.h" +#include "libcamera/internal/ipc_pipe_unixsocket.h" +#include "libcamera/internal/ipc_unixsocket.h" + +using namespace libcamera; + +LOG_DEFINE_CATEGORY({{proxy_worker_name}}) + +{%- if has_namespace %} +{% for ns in namespace -%} +using namespace {{ns}}; +{% endfor %} +{%- endif %} + +class {{proxy_worker_name}} +{ +public: + {{proxy_worker_name}}() + : ipa_(nullptr), + controlSerializer_(ControlSerializer::Role::Worker), + exit_(false) {} + + ~{{proxy_worker_name}}() {} + + void readyRead() + { + IPCUnixSocket::Payload _message; + int _retRecv = socket_.receive(&_message); + if (_retRecv) { + LOG({{proxy_worker_name}}, Error) + << "Receive message failed: " << _retRecv; + return; + } + + IPCMessage _ipcMessage(_message); + + {{cmd_enum_name}} _cmd = static_cast<{{cmd_enum_name}}>(_ipcMessage.header().cmd); + + switch (_cmd) { + case {{cmd_enum_name}}::Exit: { + exit_ = true; + break; + } + +{% for method in interface_main.methods %} + case {{cmd_enum_name}}::{{method.mojom_name|cap}}: { +{%- if method.mojom_name == "configure" %} + controlSerializer_.reset(); +{%- endif %} + {{proxy_funcs.deserialize_call(method|method_param_inputs, '_ipcMessage.data()', '_ipcMessage.fds()', false, true)|indent(16, true)}} +{% for param in method|method_param_outputs %} + {{param|name}} {{param.mojom_name}}; +{% endfor %} +{%- if method|method_return_value != "void" %} + {{method|method_return_value}} _callRet = +{%- endif -%} + ipa_->{{method.mojom_name}}({{method.parameters|params_comma_sep}} +{{- ", " if method|method_param_outputs|params_comma_sep -}} +{%- for param in method|method_param_outputs -%} +&{{param.mojom_name}}{{", " if not loop.last}} +{%- endfor -%} +); +{% if not method|is_async %} + IPCMessage::Header header = { _ipcMessage.header().cmd, _ipcMessage.header().cookie }; + IPCMessage _response(header); +{%- if method|method_return_value != "void" %} + std::vector<uint8_t> _callRetBuf; + std::tie(_callRetBuf, std::ignore) = + IPADataSerializer<{{method|method_return_value}}>::serialize(_callRet); + _response.data().insert(_response.data().end(), _callRetBuf.cbegin(), _callRetBuf.cend()); +{%- endif %} + {{proxy_funcs.serialize_call(method|method_param_outputs, "_response.data()", "_response.fds()")|indent(16, true)}} + int _ret = socket_.send(_response.payload()); + if (_ret < 0) { + LOG({{proxy_worker_name}}, Error) + << "Reply to {{method.mojom_name}}() failed: " << _ret; + } + LOG({{proxy_worker_name}}, Debug) << "Done replying to {{method.mojom_name}}()"; +{%- endif %} + break; + } +{% endfor %} + default: + LOG({{proxy_worker_name}}, Error) << "Unknown command " << _ipcMessage.header().cmd; + } + } + + int init(std::unique_ptr<IPAModule> &ipam, UniqueFD socketfd) + { + if (socket_.bind(std::move(socketfd)) < 0) { + LOG({{proxy_worker_name}}, Error) + << "IPC socket binding failed"; + return EXIT_FAILURE; + } + socket_.readyRead.connect(this, &{{proxy_worker_name}}::readyRead); + + ipa_ = dynamic_cast<{{interface_name}} *>(ipam->createInterface()); + if (!ipa_) { + LOG({{proxy_worker_name}}, Error) + << "Failed to create IPA interface instance"; + return EXIT_FAILURE; + } +{% for method in interface_event.methods %} + ipa_->{{method.mojom_name}}.connect(this, &{{proxy_worker_name}}::{{method.mojom_name}}); +{%- endfor %} + return 0; + } + + void run() + { + EventDispatcher *dispatcher = Thread::current()->eventDispatcher(); + while (!exit_) + dispatcher->processEvents(); + } + + void cleanup() + { + delete ipa_; + socket_.close(); + } + +private: + +{% for method in interface_event.methods %} +{{proxy_funcs.func_sig(proxy_name, method, "", false)|indent(8, true)}} + { + IPCMessage::Header header = { + static_cast<uint32_t>({{cmd_event_enum_name}}::{{method.mojom_name|cap}}), + 0 + }; + IPCMessage _message(header); + + {{proxy_funcs.serialize_call(method|method_param_inputs, "_message.data()", "_message.fds()")}} + + int _ret = socket_.send(_message.payload()); + if (_ret < 0) + LOG({{proxy_worker_name}}, Error) + << "Sending event {{method.mojom_name}}() failed: " << _ret; + + LOG({{proxy_worker_name}}, Debug) << "{{method.mojom_name}} done"; + } +{% endfor %} + + {{interface_name}} *ipa_; + IPCUnixSocket socket_; + + ControlSerializer controlSerializer_; + + bool exit_; +}; + +int main(int argc, char **argv) +{ +{#- \todo Handle enabling debugging more dynamically. #} + /* Uncomment this for debugging. */ +#if 0 + std::string logPath = "/tmp/libcamera.worker." + + std::to_string(getpid()) + ".log"; + logSetFile(logPath.c_str()); +#endif + + if (argc < 3) { + LOG({{proxy_worker_name}}, Error) + << "Tried to start worker with no args: " + << "expected <path to IPA so> <fd to bind unix socket>"; + return EXIT_FAILURE; + } + + UniqueFD fd(std::stoi(argv[2])); + LOG({{proxy_worker_name}}, Info) + << "Starting worker for IPA module " << argv[1] + << " with IPC fd = " << fd.get(); + + std::unique_ptr<IPAModule> ipam = std::make_unique<IPAModule>(argv[1]); + if (!ipam->isValid() || !ipam->load()) { + LOG({{proxy_worker_name}}, Error) + << "IPAModule " << argv[1] << " isn't valid"; + return EXIT_FAILURE; + } + + /* + * Shutdown of proxy worker can be pre-empted by events like + * SIGINT/SIGTERM, even before the pipeline handler can request + * shutdown. Hence, assign a new gid to prevent signals on the + * application being delivered to the proxy. + */ + if (setpgid(0, 0) < 0) { + int err = errno; + LOG({{proxy_worker_name}}, Warning) + << "Failed to set new gid: " << strerror(err); + } + + {{proxy_worker_name}} proxyWorker; + int ret = proxyWorker.init(ipam, std::move(fd)); + if (ret < 0) { + LOG({{proxy_worker_name}}, Error) + << "Failed to initialize proxy worker"; + return ret; + } + + LOG({{proxy_worker_name}}, Debug) << "Proxy worker successfully initialized"; + + proxyWorker.run(); + + proxyWorker.cleanup(); + + return 0; +} |