Message ID | 20250922100339.1455688-1-barnabas.pocze@ideasonboard.com |
---|---|
State | Accepted |
Headers | show |
Series |
|
Related | show |
Hi Barnabás, On Mon, Sep 22, 2025 at 12:03:39PM +0200, Barnabás Pőcze wrote: > Even though there is an abstract class to represent the interface of an IPA, > the threaded and IPC versions are still multiplexed using the same type, > which uses a boolean to actually dispatch to the right function. > > Instead of doing that, split the classes into "threaded" and "isolated" > variants, and make `IPAManager` choose accordingly. > > Signed-off-by: Barnabás Pőcze <barnabas.pocze@ideasonboard.com> > Reviewed-by: Paul Elder <paul.elder@ideasonboard.com> > --- > changes in v3: > * rebase > > changes in v2: > * fix typo > * rename local -> threaded, remote -> isolated > * have different log messages in the two variants > > v2: https://patchwork.libcamera.org/patch/24108/ > v1: https://patchwork.libcamera.org/patch/24056/ > --- > include/libcamera/internal/ipa_manager.h | 9 +- > .../module_ipa_proxy.cpp.tmpl | 151 +++++++++--------- > .../module_ipa_proxy.h.tmpl | 56 +++++-- > 3 files changed, 120 insertions(+), 96 deletions(-) > > diff --git a/include/libcamera/internal/ipa_manager.h b/include/libcamera/internal/ipa_manager.h > index b0b44c74a..f8ce78016 100644 > --- a/include/libcamera/internal/ipa_manager.h > +++ b/include/libcamera/internal/ipa_manager.h > @@ -44,7 +44,14 @@ public: > return nullptr; > > const GlobalConfiguration &configuration = cm->_d()->configuration(); > - std::unique_ptr<T> proxy = std::make_unique<T>(m, !self->isSignatureValid(m), configuration); > + > + auto proxy = [&]() -> std::unique_ptr<T> { > + if (self->isSignatureValid(m)) > + return std::make_unique<typename T::Threaded>(m, configuration); > + else > + return std::make_unique<typename T::Isolated>(m, configuration); > + }(); > + > if (!proxy->isValid()) { > LOG(IPAManager, Error) << "Failed to load proxy"; > return nullptr; > diff --git a/utils/codegen/ipc/generators/libcamera_templates/module_ipa_proxy.cpp.tmpl b/utils/codegen/ipc/generators/libcamera_templates/module_ipa_proxy.cpp.tmpl > index 18b4ab5e5..9bf2c58d3 100644 > --- a/utils/codegen/ipc/generators/libcamera_templates/module_ipa_proxy.cpp.tmpl > +++ b/utils/codegen/ipc/generators/libcamera_templates/module_ipa_proxy.cpp.tmpl > @@ -45,36 +45,13 @@ namespace {{ns}} { > {% endfor %} > {%- endif %} > > -{{proxy_name}}::{{proxy_name}}(IPAModule *ipam, bool isolate, const GlobalConfiguration &configuration) > - : IPAProxy(ipam, configuration), isolate_(isolate), > - controlSerializer_(ControlSerializer::Role::Proxy), seq_(0) > +{{proxy_name}}Threaded::{{proxy_name}}Threaded(IPAModule *ipam, const GlobalConfiguration &configuration) > + : {{proxy_name}}(ipam, configuration) > { > LOG(IPAProxy, Debug) > - << "initializing {{module_name}} proxy: loading IPA from " > + << "initializing {{module_name}} proxy in thread: loading IPA from " > << ipam->path(); > > - if (isolate_) { > - const std::string proxyWorkerPath = resolvePath("{{module_name}}_ipa_proxy"); > - if (proxyWorkerPath.empty()) { > - LOG(IPAProxy, Error) > - << "Failed to get proxy worker path"; > - return; > - } > - > - auto ipc = std::make_unique<IPCPipeUnixSocket>(ipam->path().c_str(), > - proxyWorkerPath.c_str()); > - if (!ipc->isConnected()) { > - LOG(IPAProxy, Error) << "Failed to create IPCPipe"; > - return; > - } > - > - ipc->recv.connect(this, &{{proxy_name}}::recvMessage); > - > - ipc_ = std::move(ipc); > - valid_ = true; > - return; > - } > - > if (!ipam->load()) > return; > > @@ -89,59 +66,16 @@ namespace {{ns}} { > proxy_.setIPA(ipa_.get()); > > {% for method in interface_event.methods %} > - ipa_->{{method.mojom_name}}.connect(this, &{{proxy_name}}::{{method.mojom_name}}Thread); > + ipa_->{{method.mojom_name}}.connect(this, &{{proxy_name}}Threaded::{{method.mojom_name}}Handler); > {%- endfor %} > > valid_ = true; > } > > -{{proxy_name}}::~{{proxy_name}}() > -{ > - if (ipc_) { > - IPCMessage::Header header = > - { static_cast<uint32_t>({{cmd_enum_name}}::Exit), seq_++ }; > - IPCMessage msg(header); > - ipc_->sendAsync(msg); > - } > -} > - > -{% if interface_event.methods|length > 0 %} > -void {{proxy_name}}::recvMessage(const IPCMessage &data) > -{ > - size_t dataSize = data.data().size(); > - {{cmd_event_enum_name}} _cmd = static_cast<{{cmd_event_enum_name}}>(data.header().cmd); > - > - switch (_cmd) { > -{%- for method in interface_event.methods %} > - case {{cmd_event_enum_name}}::{{method.mojom_name|cap}}: { > - {{method.mojom_name}}IPC(data.data().cbegin(), dataSize, data.fds()); > - break; > - } > -{%- endfor %} > - default: > - LOG(IPAProxy, Error) << "Unknown command " << static_cast<uint32_t>(_cmd); > - } > -} > -{%- endif %} > +{{proxy_name}}Threaded::~{{proxy_name}}Threaded() = default; Can't you omit the destructor from the class definition and drop this line, to let the compiler generate the default destructor ? > > {% for method in interface_main.methods %} > -{{proxy_funcs.func_sig(proxy_name, method)}} > -{ > - if (isolate_) > - return {{method.mojom_name}}IPC( > -{%- for param in method|method_param_names -%} > - {{param}}{{- ", " if not loop.last}} > -{%- endfor -%} > -); > - else > - return {{method.mojom_name}}Thread( > -{%- for param in method|method_param_names -%} > - {{param}}{{- ", " if not loop.last}} > -{%- endfor -%} > -); > -} > - > -{{proxy_funcs.func_sig(proxy_name, method, "Thread")}} > +{{proxy_funcs.func_sig(proxy_name + "Threaded", method)}} > { > {%- if method.mojom_name == "stop" %} > {{proxy_funcs.stop_thread_body()}} > @@ -181,8 +115,58 @@ void {{proxy_name}}::recvMessage(const IPCMessage &data) > ); > {%- endif %} > } > +{% endfor %} > + > +{% for method in interface_event.methods %} > +{{proxy_funcs.func_sig(proxy_name + "Threaded", method, "Handler")}} > +{ > + ASSERT(state_ != ProxyStopped); > + {{method.mojom_name}}.emit({{method.parameters|params_comma_sep}}); > +} > +{% endfor %} > + > +/* ========================================================================== */ > + > +{{proxy_name}}Isolated::{{proxy_name}}Isolated(IPAModule *ipam, const GlobalConfiguration &configuration) > + : {{proxy_name}}(ipam, configuration), > + controlSerializer_(ControlSerializer::Role::Proxy), seq_(0) > +{ > + LOG(IPAProxy, Debug) > + << "initializing {{module_name}} proxy in isolation: loading IPA from " > + << ipam->path(); > + > + const std::string proxyWorkerPath = resolvePath("{{module_name}}_ipa_proxy"); > + if (proxyWorkerPath.empty()) { > + LOG(IPAProxy, Error) > + << "Failed to get proxy worker path"; This now holds on a single line. Reviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com> > + return; > + } > + > + auto ipc = std::make_unique<IPCPipeUnixSocket>(ipam->path().c_str(), > + proxyWorkerPath.c_str()); > + if (!ipc->isConnected()) { > + LOG(IPAProxy, Error) << "Failed to create IPCPipe"; > + return; > + } > + > + ipc->recv.connect(this, &{{proxy_name}}Isolated::recvMessage); > + > + ipc_ = std::move(ipc); > + valid_ = true; > +} > > -{{proxy_funcs.func_sig(proxy_name, method, "IPC")}} > +{{proxy_name}}Isolated::~{{proxy_name}}Isolated() > +{ > + if (ipc_) { > + IPCMessage::Header header = > + { static_cast<uint32_t>({{cmd_enum_name}}::Exit), seq_++ }; > + IPCMessage msg(header); > + ipc_->sendAsync(msg); > + } > +} > + > +{% for method in interface_main.methods %} > +{{proxy_funcs.func_sig(proxy_name + "Isolated", method)}} > { > {%- if method.mojom_name == "configure" %} > controlSerializer_.reset(); > @@ -226,14 +210,25 @@ void {{proxy_name}}::recvMessage(const IPCMessage &data) > > {% endfor %} > > -{% for method in interface_event.methods %} > -{{proxy_funcs.func_sig(proxy_name, method, "Thread")}} > +void {{proxy_name}}Isolated::recvMessage(const IPCMessage &data) > { > - ASSERT(state_ != ProxyStopped); > - {{method.mojom_name}}.emit({{method.parameters|params_comma_sep}}); > + size_t dataSize = data.data().size(); > + {{cmd_event_enum_name}} _cmd = static_cast<{{cmd_event_enum_name}}>(data.header().cmd); > + > + switch (_cmd) { > +{%- for method in interface_event.methods %} > + case {{cmd_event_enum_name}}::{{method.mojom_name|cap}}: { > + {{method.mojom_name}}Handler(data.data().cbegin(), dataSize, data.fds()); > + break; > + } > +{%- endfor %} > + default: > + LOG(IPAProxy, Error) << "Unknown command " << static_cast<uint32_t>(_cmd); > + } > } > > -void {{proxy_name}}::{{method.mojom_name}}IPC( > +{% for method in interface_event.methods %} > +void {{proxy_name}}Isolated::{{method.mojom_name}}Handler( > [[maybe_unused]] std::vector<uint8_t>::const_iterator data, > [[maybe_unused]] size_t dataSize, > [[maybe_unused]] const std::vector<SharedFD> &fds) > diff --git a/utils/codegen/ipc/generators/libcamera_templates/module_ipa_proxy.h.tmpl b/utils/codegen/ipc/generators/libcamera_templates/module_ipa_proxy.h.tmpl > index 057c3ab03..ef280ca42 100644 > --- a/utils/codegen/ipc/generators/libcamera_templates/module_ipa_proxy.h.tmpl > +++ b/utils/codegen/ipc/generators/libcamera_templates/module_ipa_proxy.h.tmpl > @@ -34,29 +34,32 @@ namespace {{ns}} { > {% endfor %} > {%- endif %} > > +class {{proxy_name}}Threaded; > +class {{proxy_name}}Isolated; > + > class {{proxy_name}} : public IPAProxy, public {{interface_name}}, public Object > { > public: > - {{proxy_name}}(IPAModule *ipam, bool isolate, const GlobalConfiguration &configuration); > - ~{{proxy_name}}(); > + using Threaded = {{proxy_name}}Threaded; > + using Isolated = {{proxy_name}}Isolated; > > -{% for method in interface_main.methods %} > -{{proxy_funcs.func_sig(proxy_name, method, "", false, true)|indent(8, true)}}; > -{% endfor %} > +protected: > + using IPAProxy::IPAProxy; > +}; > > -private: > - void recvMessage(const IPCMessage &data); > +class {{proxy_name}}Threaded : public {{proxy_name}} > +{ > +public: > + {{proxy_name}}Threaded(IPAModule *ipam, const GlobalConfiguration &configuration); > + ~{{proxy_name}}Threaded(); > > {% for method in interface_main.methods %} > -{{proxy_funcs.func_sig(proxy_name, method, "Thread", false)|indent(8, true)}}; > -{{proxy_funcs.func_sig(proxy_name, method, "IPC", false)|indent(8, true)}}; > +{{proxy_funcs.func_sig(proxy_name + "Threaded", method, "", false, true)|indent(8, true)}}; > {% endfor %} > + > +private: > {% for method in interface_event.methods %} > -{{proxy_funcs.func_sig(proxy_name, method, "Thread", false)|indent(8, true)}}; > - void {{method.mojom_name}}IPC( > - std::vector<uint8_t>::const_iterator data, > - size_t dataSize, > - const std::vector<SharedFD> &fds); > +{{proxy_funcs.func_sig(proxy_name + "Threaded", method, "Handler", false)|indent(8, true)}}; > {% endfor %} > > /* Helper class to invoke async functions in another thread. */ > @@ -79,12 +82,12 @@ private: > } > {% for method in interface_main.methods %} > {%- if method|is_async %} > - {{proxy_funcs.func_sig(proxy_name, method, "", false)|indent(16)}} > + {{proxy_funcs.func_sig(proxy_name + "Threaded", method, "", false)|indent(16)}} > { > ipa_->{{method.mojom_name}}({{method.parameters|params_comma_sep}}); > } > {%- elif method.mojom_name == "start" %} > - {{proxy_funcs.func_sig(proxy_name, method, "", false)|indent(16)}} > + {{proxy_funcs.func_sig(proxy_name + "Threaded", method, "", false)|indent(16)}} > { > {%- if method|method_return_value != "void" %} > return ipa_->{{method.mojom_name}}({{method.parameters|params_comma_sep}}); > @@ -104,8 +107,27 @@ private: > Thread thread_; > ThreadProxy proxy_; > std::unique_ptr<{{interface_name}}> ipa_; > +}; > > - const bool isolate_; > +class {{proxy_name}}Isolated : public {{proxy_name}} > +{ > +public: > + {{proxy_name}}Isolated(IPAModule *ipam, const GlobalConfiguration &configuration); > + ~{{proxy_name}}Isolated(); > + > +{% for method in interface_main.methods %} > +{{proxy_funcs.func_sig(proxy_name + "Isolated", method, "", false, true)|indent(8, true)}}; > +{% endfor %} > + > +private: > + void recvMessage(const IPCMessage &data); > + > +{% for method in interface_event.methods %} > + void {{method.mojom_name}}Handler( > + std::vector<uint8_t>::const_iterator data, > + size_t dataSize, > + const std::vector<SharedFD> &fds); > +{% endfor %} > > std::unique_ptr<IPCPipeUnixSocket> ipc_; >
Hi 2025. 09. 29. 9:19 keltezéssel, Laurent Pinchart írta: > Hi Barnabás, > > On Mon, Sep 22, 2025 at 12:03:39PM +0200, Barnabás Pőcze wrote: >> Even though there is an abstract class to represent the interface of an IPA, >> the threaded and IPC versions are still multiplexed using the same type, >> which uses a boolean to actually dispatch to the right function. >> >> Instead of doing that, split the classes into "threaded" and "isolated" >> variants, and make `IPAManager` choose accordingly. >> >> Signed-off-by: Barnabás Pőcze <barnabas.pocze@ideasonboard.com> >> Reviewed-by: Paul Elder <paul.elder@ideasonboard.com> >> --- >> changes in v3: >> * rebase >> >> changes in v2: >> * fix typo >> * rename local -> threaded, remote -> isolated >> * have different log messages in the two variants >> >> v2: https://patchwork.libcamera.org/patch/24108/ >> v1: https://patchwork.libcamera.org/patch/24056/ >> --- >> include/libcamera/internal/ipa_manager.h | 9 +- >> .../module_ipa_proxy.cpp.tmpl | 151 +++++++++--------- >> .../module_ipa_proxy.h.tmpl | 56 +++++-- >> 3 files changed, 120 insertions(+), 96 deletions(-) >> >> diff --git a/include/libcamera/internal/ipa_manager.h b/include/libcamera/internal/ipa_manager.h >> index b0b44c74a..f8ce78016 100644 >> --- a/include/libcamera/internal/ipa_manager.h >> +++ b/include/libcamera/internal/ipa_manager.h >> @@ -44,7 +44,14 @@ public: >> return nullptr; >> >> const GlobalConfiguration &configuration = cm->_d()->configuration(); >> - std::unique_ptr<T> proxy = std::make_unique<T>(m, !self->isSignatureValid(m), configuration); >> + >> + auto proxy = [&]() -> std::unique_ptr<T> { >> + if (self->isSignatureValid(m)) >> + return std::make_unique<typename T::Threaded>(m, configuration); >> + else >> + return std::make_unique<typename T::Isolated>(m, configuration); >> + }(); >> + >> if (!proxy->isValid()) { >> LOG(IPAManager, Error) << "Failed to load proxy"; >> return nullptr; >> diff --git a/utils/codegen/ipc/generators/libcamera_templates/module_ipa_proxy.cpp.tmpl b/utils/codegen/ipc/generators/libcamera_templates/module_ipa_proxy.cpp.tmpl >> index 18b4ab5e5..9bf2c58d3 100644 >> --- a/utils/codegen/ipc/generators/libcamera_templates/module_ipa_proxy.cpp.tmpl >> +++ b/utils/codegen/ipc/generators/libcamera_templates/module_ipa_proxy.cpp.tmpl >> @@ -45,36 +45,13 @@ namespace {{ns}} { >> {% endfor %} >> {%- endif %} >> >> -{{proxy_name}}::{{proxy_name}}(IPAModule *ipam, bool isolate, const GlobalConfiguration &configuration) >> - : IPAProxy(ipam, configuration), isolate_(isolate), >> - controlSerializer_(ControlSerializer::Role::Proxy), seq_(0) >> +{{proxy_name}}Threaded::{{proxy_name}}Threaded(IPAModule *ipam, const GlobalConfiguration &configuration) >> + : {{proxy_name}}(ipam, configuration) >> { >> LOG(IPAProxy, Debug) >> - << "initializing {{module_name}} proxy: loading IPA from " >> + << "initializing {{module_name}} proxy in thread: loading IPA from " >> << ipam->path(); >> >> - if (isolate_) { >> - const std::string proxyWorkerPath = resolvePath("{{module_name}}_ipa_proxy"); >> - if (proxyWorkerPath.empty()) { >> - LOG(IPAProxy, Error) >> - << "Failed to get proxy worker path"; >> - return; >> - } >> - >> - auto ipc = std::make_unique<IPCPipeUnixSocket>(ipam->path().c_str(), >> - proxyWorkerPath.c_str()); >> - if (!ipc->isConnected()) { >> - LOG(IPAProxy, Error) << "Failed to create IPCPipe"; >> - return; >> - } >> - >> - ipc->recv.connect(this, &{{proxy_name}}::recvMessage); >> - >> - ipc_ = std::move(ipc); >> - valid_ = true; >> - return; >> - } >> - >> if (!ipam->load()) >> return; >> >> @@ -89,59 +66,16 @@ namespace {{ns}} { >> proxy_.setIPA(ipa_.get()); >> >> {% for method in interface_event.methods %} >> - ipa_->{{method.mojom_name}}.connect(this, &{{proxy_name}}::{{method.mojom_name}}Thread); >> + ipa_->{{method.mojom_name}}.connect(this, &{{proxy_name}}Threaded::{{method.mojom_name}}Handler); >> {%- endfor %} >> >> valid_ = true; >> } >> >> -{{proxy_name}}::~{{proxy_name}}() >> -{ >> - if (ipc_) { >> - IPCMessage::Header header = >> - { static_cast<uint32_t>({{cmd_enum_name}}::Exit), seq_++ }; >> - IPCMessage msg(header); >> - ipc_->sendAsync(msg); >> - } >> -} >> - >> -{% if interface_event.methods|length > 0 %} >> -void {{proxy_name}}::recvMessage(const IPCMessage &data) >> -{ >> - size_t dataSize = data.data().size(); >> - {{cmd_event_enum_name}} _cmd = static_cast<{{cmd_event_enum_name}}>(data.header().cmd); >> - >> - switch (_cmd) { >> -{%- for method in interface_event.methods %} >> - case {{cmd_event_enum_name}}::{{method.mojom_name|cap}}: { >> - {{method.mojom_name}}IPC(data.data().cbegin(), dataSize, data.fds()); >> - break; >> - } >> -{%- endfor %} >> - default: >> - LOG(IPAProxy, Error) << "Unknown command " << static_cast<uint32_t>(_cmd); >> - } >> -} >> -{%- endif %} >> +{{proxy_name}}Threaded::~{{proxy_name}}Threaded() = default; > > Can't you omit the destructor from the class definition and drop this > line, to let the compiler generate the default destructor ? Yes, it could be omitted. The only difference is that it would be an inline destructor, generated in the translation unit(s) where it is used. Should I change it? > >> >> {% for method in interface_main.methods %} >> -{{proxy_funcs.func_sig(proxy_name, method)}} >> -{ >> - if (isolate_) >> - return {{method.mojom_name}}IPC( >> -{%- for param in method|method_param_names -%} >> - {{param}}{{- ", " if not loop.last}} >> -{%- endfor -%} >> -); >> - else >> - return {{method.mojom_name}}Thread( >> -{%- for param in method|method_param_names -%} >> - {{param}}{{- ", " if not loop.last}} >> -{%- endfor -%} >> -); >> -} >> - >> -{{proxy_funcs.func_sig(proxy_name, method, "Thread")}} >> +{{proxy_funcs.func_sig(proxy_name + "Threaded", method)}} >> { >> {%- if method.mojom_name == "stop" %} >> {{proxy_funcs.stop_thread_body()}} >> @@ -181,8 +115,58 @@ void {{proxy_name}}::recvMessage(const IPCMessage &data) >> ); >> {%- endif %} >> } >> +{% endfor %} >> + >> +{% for method in interface_event.methods %} >> +{{proxy_funcs.func_sig(proxy_name + "Threaded", method, "Handler")}} >> +{ >> + ASSERT(state_ != ProxyStopped); >> + {{method.mojom_name}}.emit({{method.parameters|params_comma_sep}}); >> +} >> +{% endfor %} >> + >> +/* ========================================================================== */ >> + >> +{{proxy_name}}Isolated::{{proxy_name}}Isolated(IPAModule *ipam, const GlobalConfiguration &configuration) >> + : {{proxy_name}}(ipam, configuration), >> + controlSerializer_(ControlSerializer::Role::Proxy), seq_(0) >> +{ >> + LOG(IPAProxy, Debug) >> + << "initializing {{module_name}} proxy in isolation: loading IPA from " >> + << ipam->path(); >> + >> + const std::string proxyWorkerPath = resolvePath("{{module_name}}_ipa_proxy"); >> + if (proxyWorkerPath.empty()) { >> + LOG(IPAProxy, Error) >> + << "Failed to get proxy worker path"; > > This now holds on a single line. Fixed. Regards, Barnabás Pőcze > > Reviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com> > >> + return; >> + } >> + >> + auto ipc = std::make_unique<IPCPipeUnixSocket>(ipam->path().c_str(), >> + proxyWorkerPath.c_str()); >> + if (!ipc->isConnected()) { >> + LOG(IPAProxy, Error) << "Failed to create IPCPipe"; >> + return; >> + } >> + >> + ipc->recv.connect(this, &{{proxy_name}}Isolated::recvMessage); >> + >> + ipc_ = std::move(ipc); >> + valid_ = true; >> +} >> >> -{{proxy_funcs.func_sig(proxy_name, method, "IPC")}} >> +{{proxy_name}}Isolated::~{{proxy_name}}Isolated() >> +{ >> + if (ipc_) { >> + IPCMessage::Header header = >> + { static_cast<uint32_t>({{cmd_enum_name}}::Exit), seq_++ }; >> + IPCMessage msg(header); >> + ipc_->sendAsync(msg); >> + } >> +} >> + >> +{% for method in interface_main.methods %} >> +{{proxy_funcs.func_sig(proxy_name + "Isolated", method)}} >> { >> {%- if method.mojom_name == "configure" %} >> controlSerializer_.reset(); >> @@ -226,14 +210,25 @@ void {{proxy_name}}::recvMessage(const IPCMessage &data) >> >> {% endfor %} >> >> -{% for method in interface_event.methods %} >> -{{proxy_funcs.func_sig(proxy_name, method, "Thread")}} >> +void {{proxy_name}}Isolated::recvMessage(const IPCMessage &data) >> { >> - ASSERT(state_ != ProxyStopped); >> - {{method.mojom_name}}.emit({{method.parameters|params_comma_sep}}); >> + size_t dataSize = data.data().size(); >> + {{cmd_event_enum_name}} _cmd = static_cast<{{cmd_event_enum_name}}>(data.header().cmd); >> + >> + switch (_cmd) { >> +{%- for method in interface_event.methods %} >> + case {{cmd_event_enum_name}}::{{method.mojom_name|cap}}: { >> + {{method.mojom_name}}Handler(data.data().cbegin(), dataSize, data.fds()); >> + break; >> + } >> +{%- endfor %} >> + default: >> + LOG(IPAProxy, Error) << "Unknown command " << static_cast<uint32_t>(_cmd); >> + } >> } >> >> -void {{proxy_name}}::{{method.mojom_name}}IPC( >> +{% for method in interface_event.methods %} >> +void {{proxy_name}}Isolated::{{method.mojom_name}}Handler( >> [[maybe_unused]] std::vector<uint8_t>::const_iterator data, >> [[maybe_unused]] size_t dataSize, >> [[maybe_unused]] const std::vector<SharedFD> &fds) >> diff --git a/utils/codegen/ipc/generators/libcamera_templates/module_ipa_proxy.h.tmpl b/utils/codegen/ipc/generators/libcamera_templates/module_ipa_proxy.h.tmpl >> index 057c3ab03..ef280ca42 100644 >> --- a/utils/codegen/ipc/generators/libcamera_templates/module_ipa_proxy.h.tmpl >> +++ b/utils/codegen/ipc/generators/libcamera_templates/module_ipa_proxy.h.tmpl >> @@ -34,29 +34,32 @@ namespace {{ns}} { >> {% endfor %} >> {%- endif %} >> >> +class {{proxy_name}}Threaded; >> +class {{proxy_name}}Isolated; >> + >> class {{proxy_name}} : public IPAProxy, public {{interface_name}}, public Object >> { >> public: >> - {{proxy_name}}(IPAModule *ipam, bool isolate, const GlobalConfiguration &configuration); >> - ~{{proxy_name}}(); >> + using Threaded = {{proxy_name}}Threaded; >> + using Isolated = {{proxy_name}}Isolated; >> >> -{% for method in interface_main.methods %} >> -{{proxy_funcs.func_sig(proxy_name, method, "", false, true)|indent(8, true)}}; >> -{% endfor %} >> +protected: >> + using IPAProxy::IPAProxy; >> +}; >> >> -private: >> - void recvMessage(const IPCMessage &data); >> +class {{proxy_name}}Threaded : public {{proxy_name}} >> +{ >> +public: >> + {{proxy_name}}Threaded(IPAModule *ipam, const GlobalConfiguration &configuration); >> + ~{{proxy_name}}Threaded(); >> >> {% for method in interface_main.methods %} >> -{{proxy_funcs.func_sig(proxy_name, method, "Thread", false)|indent(8, true)}}; >> -{{proxy_funcs.func_sig(proxy_name, method, "IPC", false)|indent(8, true)}}; >> +{{proxy_funcs.func_sig(proxy_name + "Threaded", method, "", false, true)|indent(8, true)}}; >> {% endfor %} >> + >> +private: >> {% for method in interface_event.methods %} >> -{{proxy_funcs.func_sig(proxy_name, method, "Thread", false)|indent(8, true)}}; >> - void {{method.mojom_name}}IPC( >> - std::vector<uint8_t>::const_iterator data, >> - size_t dataSize, >> - const std::vector<SharedFD> &fds); >> +{{proxy_funcs.func_sig(proxy_name + "Threaded", method, "Handler", false)|indent(8, true)}}; >> {% endfor %} >> >> /* Helper class to invoke async functions in another thread. */ >> @@ -79,12 +82,12 @@ private: >> } >> {% for method in interface_main.methods %} >> {%- if method|is_async %} >> - {{proxy_funcs.func_sig(proxy_name, method, "", false)|indent(16)}} >> + {{proxy_funcs.func_sig(proxy_name + "Threaded", method, "", false)|indent(16)}} >> { >> ipa_->{{method.mojom_name}}({{method.parameters|params_comma_sep}}); >> } >> {%- elif method.mojom_name == "start" %} >> - {{proxy_funcs.func_sig(proxy_name, method, "", false)|indent(16)}} >> + {{proxy_funcs.func_sig(proxy_name + "Threaded", method, "", false)|indent(16)}} >> { >> {%- if method|method_return_value != "void" %} >> return ipa_->{{method.mojom_name}}({{method.parameters|params_comma_sep}}); >> @@ -104,8 +107,27 @@ private: >> Thread thread_; >> ThreadProxy proxy_; >> std::unique_ptr<{{interface_name}}> ipa_; >> +}; >> >> - const bool isolate_; >> +class {{proxy_name}}Isolated : public {{proxy_name}} >> +{ >> +public: >> + {{proxy_name}}Isolated(IPAModule *ipam, const GlobalConfiguration &configuration); >> + ~{{proxy_name}}Isolated(); >> + >> +{% for method in interface_main.methods %} >> +{{proxy_funcs.func_sig(proxy_name + "Isolated", method, "", false, true)|indent(8, true)}}; >> +{% endfor %} >> + >> +private: >> + void recvMessage(const IPCMessage &data); >> + >> +{% for method in interface_event.methods %} >> + void {{method.mojom_name}}Handler( >> + std::vector<uint8_t>::const_iterator data, >> + size_t dataSize, >> + const std::vector<SharedFD> &fds); >> +{% endfor %} >> >> std::unique_ptr<IPCPipeUnixSocket> ipc_; >> >
On Mon, Sep 29, 2025 at 09:54:49AM +0200, Barnabás Pőcze wrote: > 2025. 09. 29. 9:19 keltezéssel, Laurent Pinchart írta: > > On Mon, Sep 22, 2025 at 12:03:39PM +0200, Barnabás Pőcze wrote: > >> Even though there is an abstract class to represent the interface of an IPA, > >> the threaded and IPC versions are still multiplexed using the same type, > >> which uses a boolean to actually dispatch to the right function. > >> > >> Instead of doing that, split the classes into "threaded" and "isolated" > >> variants, and make `IPAManager` choose accordingly. > >> > >> Signed-off-by: Barnabás Pőcze <barnabas.pocze@ideasonboard.com> > >> Reviewed-by: Paul Elder <paul.elder@ideasonboard.com> > >> --- > >> changes in v3: > >> * rebase > >> > >> changes in v2: > >> * fix typo > >> * rename local -> threaded, remote -> isolated > >> * have different log messages in the two variants > >> > >> v2: https://patchwork.libcamera.org/patch/24108/ > >> v1: https://patchwork.libcamera.org/patch/24056/ > >> --- > >> include/libcamera/internal/ipa_manager.h | 9 +- > >> .../module_ipa_proxy.cpp.tmpl | 151 +++++++++--------- > >> .../module_ipa_proxy.h.tmpl | 56 +++++-- > >> 3 files changed, 120 insertions(+), 96 deletions(-) > >> > >> diff --git a/include/libcamera/internal/ipa_manager.h b/include/libcamera/internal/ipa_manager.h > >> index b0b44c74a..f8ce78016 100644 > >> --- a/include/libcamera/internal/ipa_manager.h > >> +++ b/include/libcamera/internal/ipa_manager.h > >> @@ -44,7 +44,14 @@ public: > >> return nullptr; > >> > >> const GlobalConfiguration &configuration = cm->_d()->configuration(); > >> - std::unique_ptr<T> proxy = std::make_unique<T>(m, !self->isSignatureValid(m), configuration); > >> + > >> + auto proxy = [&]() -> std::unique_ptr<T> { > >> + if (self->isSignatureValid(m)) > >> + return std::make_unique<typename T::Threaded>(m, configuration); > >> + else > >> + return std::make_unique<typename T::Isolated>(m, configuration); > >> + }(); > >> + > >> if (!proxy->isValid()) { > >> LOG(IPAManager, Error) << "Failed to load proxy"; > >> return nullptr; > >> diff --git a/utils/codegen/ipc/generators/libcamera_templates/module_ipa_proxy.cpp.tmpl b/utils/codegen/ipc/generators/libcamera_templates/module_ipa_proxy.cpp.tmpl > >> index 18b4ab5e5..9bf2c58d3 100644 > >> --- a/utils/codegen/ipc/generators/libcamera_templates/module_ipa_proxy.cpp.tmpl > >> +++ b/utils/codegen/ipc/generators/libcamera_templates/module_ipa_proxy.cpp.tmpl > >> @@ -45,36 +45,13 @@ namespace {{ns}} { > >> {% endfor %} > >> {%- endif %} > >> > >> -{{proxy_name}}::{{proxy_name}}(IPAModule *ipam, bool isolate, const GlobalConfiguration &configuration) > >> - : IPAProxy(ipam, configuration), isolate_(isolate), > >> - controlSerializer_(ControlSerializer::Role::Proxy), seq_(0) > >> +{{proxy_name}}Threaded::{{proxy_name}}Threaded(IPAModule *ipam, const GlobalConfiguration &configuration) > >> + : {{proxy_name}}(ipam, configuration) > >> { > >> LOG(IPAProxy, Debug) > >> - << "initializing {{module_name}} proxy: loading IPA from " > >> + << "initializing {{module_name}} proxy in thread: loading IPA from " > >> << ipam->path(); > >> > >> - if (isolate_) { > >> - const std::string proxyWorkerPath = resolvePath("{{module_name}}_ipa_proxy"); > >> - if (proxyWorkerPath.empty()) { > >> - LOG(IPAProxy, Error) > >> - << "Failed to get proxy worker path"; > >> - return; > >> - } > >> - > >> - auto ipc = std::make_unique<IPCPipeUnixSocket>(ipam->path().c_str(), > >> - proxyWorkerPath.c_str()); > >> - if (!ipc->isConnected()) { > >> - LOG(IPAProxy, Error) << "Failed to create IPCPipe"; > >> - return; > >> - } > >> - > >> - ipc->recv.connect(this, &{{proxy_name}}::recvMessage); > >> - > >> - ipc_ = std::move(ipc); > >> - valid_ = true; > >> - return; > >> - } > >> - > >> if (!ipam->load()) > >> return; > >> > >> @@ -89,59 +66,16 @@ namespace {{ns}} { > >> proxy_.setIPA(ipa_.get()); > >> > >> {% for method in interface_event.methods %} > >> - ipa_->{{method.mojom_name}}.connect(this, &{{proxy_name}}::{{method.mojom_name}}Thread); > >> + ipa_->{{method.mojom_name}}.connect(this, &{{proxy_name}}Threaded::{{method.mojom_name}}Handler); > >> {%- endfor %} > >> > >> valid_ = true; > >> } > >> > >> -{{proxy_name}}::~{{proxy_name}}() > >> -{ > >> - if (ipc_) { > >> - IPCMessage::Header header = > >> - { static_cast<uint32_t>({{cmd_enum_name}}::Exit), seq_++ }; > >> - IPCMessage msg(header); > >> - ipc_->sendAsync(msg); > >> - } > >> -} > >> - > >> -{% if interface_event.methods|length > 0 %} > >> -void {{proxy_name}}::recvMessage(const IPCMessage &data) > >> -{ > >> - size_t dataSize = data.data().size(); > >> - {{cmd_event_enum_name}} _cmd = static_cast<{{cmd_event_enum_name}}>(data.header().cmd); > >> - > >> - switch (_cmd) { > >> -{%- for method in interface_event.methods %} > >> - case {{cmd_event_enum_name}}::{{method.mojom_name|cap}}: { > >> - {{method.mojom_name}}IPC(data.data().cbegin(), dataSize, data.fds()); > >> - break; > >> - } > >> -{%- endfor %} > >> - default: > >> - LOG(IPAProxy, Error) << "Unknown command " << static_cast<uint32_t>(_cmd); > >> - } > >> -} > >> -{%- endif %} > >> +{{proxy_name}}Threaded::~{{proxy_name}}Threaded() = default; > > > > Can't you omit the destructor from the class definition and drop this > > line, to let the compiler generate the default destructor ? > > Yes, it could be omitted. The only difference is that it would be an inline > destructor, generated in the translation unit(s) where it is used. Should I > change it? Ah right. You can keep it here if you think it's better. Up to you. > >> > >> {% for method in interface_main.methods %} > >> -{{proxy_funcs.func_sig(proxy_name, method)}} > >> -{ > >> - if (isolate_) > >> - return {{method.mojom_name}}IPC( > >> -{%- for param in method|method_param_names -%} > >> - {{param}}{{- ", " if not loop.last}} > >> -{%- endfor -%} > >> -); > >> - else > >> - return {{method.mojom_name}}Thread( > >> -{%- for param in method|method_param_names -%} > >> - {{param}}{{- ", " if not loop.last}} > >> -{%- endfor -%} > >> -); > >> -} > >> - > >> -{{proxy_funcs.func_sig(proxy_name, method, "Thread")}} > >> +{{proxy_funcs.func_sig(proxy_name + "Threaded", method)}} > >> { > >> {%- if method.mojom_name == "stop" %} > >> {{proxy_funcs.stop_thread_body()}} > >> @@ -181,8 +115,58 @@ void {{proxy_name}}::recvMessage(const IPCMessage &data) > >> ); > >> {%- endif %} > >> } > >> +{% endfor %} > >> + > >> +{% for method in interface_event.methods %} > >> +{{proxy_funcs.func_sig(proxy_name + "Threaded", method, "Handler")}} > >> +{ > >> + ASSERT(state_ != ProxyStopped); > >> + {{method.mojom_name}}.emit({{method.parameters|params_comma_sep}}); > >> +} > >> +{% endfor %} > >> + > >> +/* ========================================================================== */ > >> + > >> +{{proxy_name}}Isolated::{{proxy_name}}Isolated(IPAModule *ipam, const GlobalConfiguration &configuration) > >> + : {{proxy_name}}(ipam, configuration), > >> + controlSerializer_(ControlSerializer::Role::Proxy), seq_(0) > >> +{ > >> + LOG(IPAProxy, Debug) > >> + << "initializing {{module_name}} proxy in isolation: loading IPA from " > >> + << ipam->path(); > >> + > >> + const std::string proxyWorkerPath = resolvePath("{{module_name}}_ipa_proxy"); > >> + if (proxyWorkerPath.empty()) { > >> + LOG(IPAProxy, Error) > >> + << "Failed to get proxy worker path"; > > > > This now holds on a single line. > > Fixed. > > > Reviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com> > > > >> + return; > >> + } > >> + > >> + auto ipc = std::make_unique<IPCPipeUnixSocket>(ipam->path().c_str(), > >> + proxyWorkerPath.c_str()); > >> + if (!ipc->isConnected()) { > >> + LOG(IPAProxy, Error) << "Failed to create IPCPipe"; > >> + return; > >> + } > >> + > >> + ipc->recv.connect(this, &{{proxy_name}}Isolated::recvMessage); > >> + > >> + ipc_ = std::move(ipc); > >> + valid_ = true; > >> +} > >> > >> -{{proxy_funcs.func_sig(proxy_name, method, "IPC")}} > >> +{{proxy_name}}Isolated::~{{proxy_name}}Isolated() > >> +{ > >> + if (ipc_) { > >> + IPCMessage::Header header = > >> + { static_cast<uint32_t>({{cmd_enum_name}}::Exit), seq_++ }; > >> + IPCMessage msg(header); > >> + ipc_->sendAsync(msg); > >> + } > >> +} > >> + > >> +{% for method in interface_main.methods %} > >> +{{proxy_funcs.func_sig(proxy_name + "Isolated", method)}} > >> { > >> {%- if method.mojom_name == "configure" %} > >> controlSerializer_.reset(); > >> @@ -226,14 +210,25 @@ void {{proxy_name}}::recvMessage(const IPCMessage &data) > >> > >> {% endfor %} > >> > >> -{% for method in interface_event.methods %} > >> -{{proxy_funcs.func_sig(proxy_name, method, "Thread")}} > >> +void {{proxy_name}}Isolated::recvMessage(const IPCMessage &data) > >> { > >> - ASSERT(state_ != ProxyStopped); > >> - {{method.mojom_name}}.emit({{method.parameters|params_comma_sep}}); > >> + size_t dataSize = data.data().size(); > >> + {{cmd_event_enum_name}} _cmd = static_cast<{{cmd_event_enum_name}}>(data.header().cmd); > >> + > >> + switch (_cmd) { > >> +{%- for method in interface_event.methods %} > >> + case {{cmd_event_enum_name}}::{{method.mojom_name|cap}}: { > >> + {{method.mojom_name}}Handler(data.data().cbegin(), dataSize, data.fds()); > >> + break; > >> + } > >> +{%- endfor %} > >> + default: > >> + LOG(IPAProxy, Error) << "Unknown command " << static_cast<uint32_t>(_cmd); > >> + } > >> } > >> > >> -void {{proxy_name}}::{{method.mojom_name}}IPC( > >> +{% for method in interface_event.methods %} > >> +void {{proxy_name}}Isolated::{{method.mojom_name}}Handler( > >> [[maybe_unused]] std::vector<uint8_t>::const_iterator data, > >> [[maybe_unused]] size_t dataSize, > >> [[maybe_unused]] const std::vector<SharedFD> &fds) > >> diff --git a/utils/codegen/ipc/generators/libcamera_templates/module_ipa_proxy.h.tmpl b/utils/codegen/ipc/generators/libcamera_templates/module_ipa_proxy.h.tmpl > >> index 057c3ab03..ef280ca42 100644 > >> --- a/utils/codegen/ipc/generators/libcamera_templates/module_ipa_proxy.h.tmpl > >> +++ b/utils/codegen/ipc/generators/libcamera_templates/module_ipa_proxy.h.tmpl > >> @@ -34,29 +34,32 @@ namespace {{ns}} { > >> {% endfor %} > >> {%- endif %} > >> > >> +class {{proxy_name}}Threaded; > >> +class {{proxy_name}}Isolated; > >> + > >> class {{proxy_name}} : public IPAProxy, public {{interface_name}}, public Object > >> { > >> public: > >> - {{proxy_name}}(IPAModule *ipam, bool isolate, const GlobalConfiguration &configuration); > >> - ~{{proxy_name}}(); > >> + using Threaded = {{proxy_name}}Threaded; > >> + using Isolated = {{proxy_name}}Isolated; > >> > >> -{% for method in interface_main.methods %} > >> -{{proxy_funcs.func_sig(proxy_name, method, "", false, true)|indent(8, true)}}; > >> -{% endfor %} > >> +protected: > >> + using IPAProxy::IPAProxy; > >> +}; > >> > >> -private: > >> - void recvMessage(const IPCMessage &data); > >> +class {{proxy_name}}Threaded : public {{proxy_name}} > >> +{ > >> +public: > >> + {{proxy_name}}Threaded(IPAModule *ipam, const GlobalConfiguration &configuration); > >> + ~{{proxy_name}}Threaded(); > >> > >> {% for method in interface_main.methods %} > >> -{{proxy_funcs.func_sig(proxy_name, method, "Thread", false)|indent(8, true)}}; > >> -{{proxy_funcs.func_sig(proxy_name, method, "IPC", false)|indent(8, true)}}; > >> +{{proxy_funcs.func_sig(proxy_name + "Threaded", method, "", false, true)|indent(8, true)}}; > >> {% endfor %} > >> + > >> +private: > >> {% for method in interface_event.methods %} > >> -{{proxy_funcs.func_sig(proxy_name, method, "Thread", false)|indent(8, true)}}; > >> - void {{method.mojom_name}}IPC( > >> - std::vector<uint8_t>::const_iterator data, > >> - size_t dataSize, > >> - const std::vector<SharedFD> &fds); > >> +{{proxy_funcs.func_sig(proxy_name + "Threaded", method, "Handler", false)|indent(8, true)}}; > >> {% endfor %} > >> > >> /* Helper class to invoke async functions in another thread. */ > >> @@ -79,12 +82,12 @@ private: > >> } > >> {% for method in interface_main.methods %} > >> {%- if method|is_async %} > >> - {{proxy_funcs.func_sig(proxy_name, method, "", false)|indent(16)}} > >> + {{proxy_funcs.func_sig(proxy_name + "Threaded", method, "", false)|indent(16)}} > >> { > >> ipa_->{{method.mojom_name}}({{method.parameters|params_comma_sep}}); > >> } > >> {%- elif method.mojom_name == "start" %} > >> - {{proxy_funcs.func_sig(proxy_name, method, "", false)|indent(16)}} > >> + {{proxy_funcs.func_sig(proxy_name + "Threaded", method, "", false)|indent(16)}} > >> { > >> {%- if method|method_return_value != "void" %} > >> return ipa_->{{method.mojom_name}}({{method.parameters|params_comma_sep}}); > >> @@ -104,8 +107,27 @@ private: > >> Thread thread_; > >> ThreadProxy proxy_; > >> std::unique_ptr<{{interface_name}}> ipa_; > >> +}; > >> > >> - const bool isolate_; > >> +class {{proxy_name}}Isolated : public {{proxy_name}} > >> +{ > >> +public: > >> + {{proxy_name}}Isolated(IPAModule *ipam, const GlobalConfiguration &configuration); > >> + ~{{proxy_name}}Isolated(); > >> + > >> +{% for method in interface_main.methods %} > >> +{{proxy_funcs.func_sig(proxy_name + "Isolated", method, "", false, true)|indent(8, true)}}; > >> +{% endfor %} > >> + > >> +private: > >> + void recvMessage(const IPCMessage &data); > >> + > >> +{% for method in interface_event.methods %} > >> + void {{method.mojom_name}}Handler( > >> + std::vector<uint8_t>::const_iterator data, > >> + size_t dataSize, > >> + const std::vector<SharedFD> &fds); > >> +{% endfor %} > >> > >> std::unique_ptr<IPCPipeUnixSocket> ipc_; > >>
diff --git a/include/libcamera/internal/ipa_manager.h b/include/libcamera/internal/ipa_manager.h index b0b44c74a..f8ce78016 100644 --- a/include/libcamera/internal/ipa_manager.h +++ b/include/libcamera/internal/ipa_manager.h @@ -44,7 +44,14 @@ public: return nullptr; const GlobalConfiguration &configuration = cm->_d()->configuration(); - std::unique_ptr<T> proxy = std::make_unique<T>(m, !self->isSignatureValid(m), configuration); + + auto proxy = [&]() -> std::unique_ptr<T> { + if (self->isSignatureValid(m)) + return std::make_unique<typename T::Threaded>(m, configuration); + else + return std::make_unique<typename T::Isolated>(m, configuration); + }(); + if (!proxy->isValid()) { LOG(IPAManager, Error) << "Failed to load proxy"; return nullptr; diff --git a/utils/codegen/ipc/generators/libcamera_templates/module_ipa_proxy.cpp.tmpl b/utils/codegen/ipc/generators/libcamera_templates/module_ipa_proxy.cpp.tmpl index 18b4ab5e5..9bf2c58d3 100644 --- a/utils/codegen/ipc/generators/libcamera_templates/module_ipa_proxy.cpp.tmpl +++ b/utils/codegen/ipc/generators/libcamera_templates/module_ipa_proxy.cpp.tmpl @@ -45,36 +45,13 @@ namespace {{ns}} { {% endfor %} {%- endif %} -{{proxy_name}}::{{proxy_name}}(IPAModule *ipam, bool isolate, const GlobalConfiguration &configuration) - : IPAProxy(ipam, configuration), isolate_(isolate), - controlSerializer_(ControlSerializer::Role::Proxy), seq_(0) +{{proxy_name}}Threaded::{{proxy_name}}Threaded(IPAModule *ipam, const GlobalConfiguration &configuration) + : {{proxy_name}}(ipam, configuration) { LOG(IPAProxy, Debug) - << "initializing {{module_name}} proxy: loading IPA from " + << "initializing {{module_name}} proxy in thread: loading IPA from " << ipam->path(); - if (isolate_) { - const std::string proxyWorkerPath = resolvePath("{{module_name}}_ipa_proxy"); - if (proxyWorkerPath.empty()) { - LOG(IPAProxy, Error) - << "Failed to get proxy worker path"; - return; - } - - auto ipc = std::make_unique<IPCPipeUnixSocket>(ipam->path().c_str(), - proxyWorkerPath.c_str()); - if (!ipc->isConnected()) { - LOG(IPAProxy, Error) << "Failed to create IPCPipe"; - return; - } - - ipc->recv.connect(this, &{{proxy_name}}::recvMessage); - - ipc_ = std::move(ipc); - valid_ = true; - return; - } - if (!ipam->load()) return; @@ -89,59 +66,16 @@ namespace {{ns}} { proxy_.setIPA(ipa_.get()); {% for method in interface_event.methods %} - ipa_->{{method.mojom_name}}.connect(this, &{{proxy_name}}::{{method.mojom_name}}Thread); + ipa_->{{method.mojom_name}}.connect(this, &{{proxy_name}}Threaded::{{method.mojom_name}}Handler); {%- endfor %} valid_ = true; } -{{proxy_name}}::~{{proxy_name}}() -{ - if (ipc_) { - IPCMessage::Header header = - { static_cast<uint32_t>({{cmd_enum_name}}::Exit), seq_++ }; - IPCMessage msg(header); - ipc_->sendAsync(msg); - } -} - -{% if interface_event.methods|length > 0 %} -void {{proxy_name}}::recvMessage(const IPCMessage &data) -{ - size_t dataSize = data.data().size(); - {{cmd_event_enum_name}} _cmd = static_cast<{{cmd_event_enum_name}}>(data.header().cmd); - - switch (_cmd) { -{%- for method in interface_event.methods %} - case {{cmd_event_enum_name}}::{{method.mojom_name|cap}}: { - {{method.mojom_name}}IPC(data.data().cbegin(), dataSize, data.fds()); - break; - } -{%- endfor %} - default: - LOG(IPAProxy, Error) << "Unknown command " << static_cast<uint32_t>(_cmd); - } -} -{%- endif %} +{{proxy_name}}Threaded::~{{proxy_name}}Threaded() = default; {% for method in interface_main.methods %} -{{proxy_funcs.func_sig(proxy_name, method)}} -{ - if (isolate_) - return {{method.mojom_name}}IPC( -{%- for param in method|method_param_names -%} - {{param}}{{- ", " if not loop.last}} -{%- endfor -%} -); - else - return {{method.mojom_name}}Thread( -{%- for param in method|method_param_names -%} - {{param}}{{- ", " if not loop.last}} -{%- endfor -%} -); -} - -{{proxy_funcs.func_sig(proxy_name, method, "Thread")}} +{{proxy_funcs.func_sig(proxy_name + "Threaded", method)}} { {%- if method.mojom_name == "stop" %} {{proxy_funcs.stop_thread_body()}} @@ -181,8 +115,58 @@ void {{proxy_name}}::recvMessage(const IPCMessage &data) ); {%- endif %} } +{% endfor %} + +{% for method in interface_event.methods %} +{{proxy_funcs.func_sig(proxy_name + "Threaded", method, "Handler")}} +{ + ASSERT(state_ != ProxyStopped); + {{method.mojom_name}}.emit({{method.parameters|params_comma_sep}}); +} +{% endfor %} + +/* ========================================================================== */ + +{{proxy_name}}Isolated::{{proxy_name}}Isolated(IPAModule *ipam, const GlobalConfiguration &configuration) + : {{proxy_name}}(ipam, configuration), + controlSerializer_(ControlSerializer::Role::Proxy), seq_(0) +{ + LOG(IPAProxy, Debug) + << "initializing {{module_name}} proxy in isolation: loading IPA from " + << ipam->path(); + + const std::string proxyWorkerPath = resolvePath("{{module_name}}_ipa_proxy"); + if (proxyWorkerPath.empty()) { + LOG(IPAProxy, Error) + << "Failed to get proxy worker path"; + return; + } + + auto ipc = std::make_unique<IPCPipeUnixSocket>(ipam->path().c_str(), + proxyWorkerPath.c_str()); + if (!ipc->isConnected()) { + LOG(IPAProxy, Error) << "Failed to create IPCPipe"; + return; + } + + ipc->recv.connect(this, &{{proxy_name}}Isolated::recvMessage); + + ipc_ = std::move(ipc); + valid_ = true; +} -{{proxy_funcs.func_sig(proxy_name, method, "IPC")}} +{{proxy_name}}Isolated::~{{proxy_name}}Isolated() +{ + if (ipc_) { + IPCMessage::Header header = + { static_cast<uint32_t>({{cmd_enum_name}}::Exit), seq_++ }; + IPCMessage msg(header); + ipc_->sendAsync(msg); + } +} + +{% for method in interface_main.methods %} +{{proxy_funcs.func_sig(proxy_name + "Isolated", method)}} { {%- if method.mojom_name == "configure" %} controlSerializer_.reset(); @@ -226,14 +210,25 @@ void {{proxy_name}}::recvMessage(const IPCMessage &data) {% endfor %} -{% for method in interface_event.methods %} -{{proxy_funcs.func_sig(proxy_name, method, "Thread")}} +void {{proxy_name}}Isolated::recvMessage(const IPCMessage &data) { - ASSERT(state_ != ProxyStopped); - {{method.mojom_name}}.emit({{method.parameters|params_comma_sep}}); + size_t dataSize = data.data().size(); + {{cmd_event_enum_name}} _cmd = static_cast<{{cmd_event_enum_name}}>(data.header().cmd); + + switch (_cmd) { +{%- for method in interface_event.methods %} + case {{cmd_event_enum_name}}::{{method.mojom_name|cap}}: { + {{method.mojom_name}}Handler(data.data().cbegin(), dataSize, data.fds()); + break; + } +{%- endfor %} + default: + LOG(IPAProxy, Error) << "Unknown command " << static_cast<uint32_t>(_cmd); + } } -void {{proxy_name}}::{{method.mojom_name}}IPC( +{% for method in interface_event.methods %} +void {{proxy_name}}Isolated::{{method.mojom_name}}Handler( [[maybe_unused]] std::vector<uint8_t>::const_iterator data, [[maybe_unused]] size_t dataSize, [[maybe_unused]] const std::vector<SharedFD> &fds) diff --git a/utils/codegen/ipc/generators/libcamera_templates/module_ipa_proxy.h.tmpl b/utils/codegen/ipc/generators/libcamera_templates/module_ipa_proxy.h.tmpl index 057c3ab03..ef280ca42 100644 --- a/utils/codegen/ipc/generators/libcamera_templates/module_ipa_proxy.h.tmpl +++ b/utils/codegen/ipc/generators/libcamera_templates/module_ipa_proxy.h.tmpl @@ -34,29 +34,32 @@ namespace {{ns}} { {% endfor %} {%- endif %} +class {{proxy_name}}Threaded; +class {{proxy_name}}Isolated; + class {{proxy_name}} : public IPAProxy, public {{interface_name}}, public Object { public: - {{proxy_name}}(IPAModule *ipam, bool isolate, const GlobalConfiguration &configuration); - ~{{proxy_name}}(); + using Threaded = {{proxy_name}}Threaded; + using Isolated = {{proxy_name}}Isolated; -{% for method in interface_main.methods %} -{{proxy_funcs.func_sig(proxy_name, method, "", false, true)|indent(8, true)}}; -{% endfor %} +protected: + using IPAProxy::IPAProxy; +}; -private: - void recvMessage(const IPCMessage &data); +class {{proxy_name}}Threaded : public {{proxy_name}} +{ +public: + {{proxy_name}}Threaded(IPAModule *ipam, const GlobalConfiguration &configuration); + ~{{proxy_name}}Threaded(); {% for method in interface_main.methods %} -{{proxy_funcs.func_sig(proxy_name, method, "Thread", false)|indent(8, true)}}; -{{proxy_funcs.func_sig(proxy_name, method, "IPC", false)|indent(8, true)}}; +{{proxy_funcs.func_sig(proxy_name + "Threaded", method, "", false, true)|indent(8, true)}}; {% endfor %} + +private: {% for method in interface_event.methods %} -{{proxy_funcs.func_sig(proxy_name, method, "Thread", false)|indent(8, true)}}; - void {{method.mojom_name}}IPC( - std::vector<uint8_t>::const_iterator data, - size_t dataSize, - const std::vector<SharedFD> &fds); +{{proxy_funcs.func_sig(proxy_name + "Threaded", method, "Handler", false)|indent(8, true)}}; {% endfor %} /* Helper class to invoke async functions in another thread. */ @@ -79,12 +82,12 @@ private: } {% for method in interface_main.methods %} {%- if method|is_async %} - {{proxy_funcs.func_sig(proxy_name, method, "", false)|indent(16)}} + {{proxy_funcs.func_sig(proxy_name + "Threaded", method, "", false)|indent(16)}} { ipa_->{{method.mojom_name}}({{method.parameters|params_comma_sep}}); } {%- elif method.mojom_name == "start" %} - {{proxy_funcs.func_sig(proxy_name, method, "", false)|indent(16)}} + {{proxy_funcs.func_sig(proxy_name + "Threaded", method, "", false)|indent(16)}} { {%- if method|method_return_value != "void" %} return ipa_->{{method.mojom_name}}({{method.parameters|params_comma_sep}}); @@ -104,8 +107,27 @@ private: Thread thread_; ThreadProxy proxy_; std::unique_ptr<{{interface_name}}> ipa_; +}; - const bool isolate_; +class {{proxy_name}}Isolated : public {{proxy_name}} +{ +public: + {{proxy_name}}Isolated(IPAModule *ipam, const GlobalConfiguration &configuration); + ~{{proxy_name}}Isolated(); + +{% for method in interface_main.methods %} +{{proxy_funcs.func_sig(proxy_name + "Isolated", method, "", false, true)|indent(8, true)}}; +{% endfor %} + +private: + void recvMessage(const IPCMessage &data); + +{% for method in interface_event.methods %} + void {{method.mojom_name}}Handler( + std::vector<uint8_t>::const_iterator data, + size_t dataSize, + const std::vector<SharedFD> &fds); +{% endfor %} std::unique_ptr<IPCPipeUnixSocket> ipc_;