From patchwork Thu Jul 11 18:50:40 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Paul Elder X-Patchwork-Id: 1660 Return-Path: Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [213.167.242.64]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 50A8E60BC8 for ; Thu, 11 Jul 2019 20:51:06 +0200 (CEST) Received: from neptunite.amanokami.net (softbank126163157105.bbtec.net [126.163.157.105]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id 9383331C; Thu, 11 Jul 2019 20:51:04 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1562871065; bh=CdkgtGCmPgpwxMUM6L27K4CxWKp5s6buD0af5i9fY3c=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=cbfUAxam5v0IG1YmN3FEB/3qJ38vDD635hvcb/fM8Emj2lgMJNZ/tOU0Kb5LK3NRl 3F7u5tXlFEx82HNOR/bb7mXEl0KC/rmEIq3U7jUTpORb6agpKjgCYVW/+QyeKtA1dD cXpd+LHl/XQy7JBdTSSHP6R3mNBR5+kHeLHW9bvA= From: Paul Elder To: libcamera-devel@lists.libcamera.org Date: Fri, 12 Jul 2019 03:50:40 +0900 Message-Id: <20190711185047.11671-2-paul.elder@ideasonboard.com> X-Mailer: git-send-email 2.20.1 In-Reply-To: <20190711185047.11671-1-paul.elder@ideasonboard.com> References: <20190711185047.11671-1-paul.elder@ideasonboard.com> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v4 1/8] libcamera: ipa_module_info: add license field X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Thu, 11 Jul 2019 18:51:06 -0000 Add a field to IPAModuleInfo to contain the license of the module. This license field will be used to determine whether the IPA module should be run in an isolated process or not. If the license is open source, then the IPA module will be allowed to run without process isolation, if the user enables it. If the license is not open source, then the IPA module will be run with process isolation. Update the dummy IPA and IPA test to conform to the new struct layout. Signed-off-by: Paul Elder Reviewed-by: Laurent Pinchart --- Changes in v4: - improve documentation Changes in v3: - make license field SPDX New patch in v2 - this replaces the isolate flag that was used in v1 include/libcamera/ipa/ipa_module_info.h | 1 + src/ipa/ipa_dummy.cpp | 1 + src/libcamera/ipa_module.cpp | 23 +++++++++++++++++++++++ test/ipa/ipa_test.cpp | 1 + 4 files changed, 26 insertions(+) diff --git a/include/libcamera/ipa/ipa_module_info.h b/include/libcamera/ipa/ipa_module_info.h index 585f753..d9e33c1 100644 --- a/include/libcamera/ipa/ipa_module_info.h +++ b/include/libcamera/ipa/ipa_module_info.h @@ -18,6 +18,7 @@ struct IPAModuleInfo { uint32_t pipelineVersion; char pipelineName[256]; char name[256]; + char license[64]; } __attribute__((packed)); extern "C" { diff --git a/src/ipa/ipa_dummy.cpp b/src/ipa/ipa_dummy.cpp index ee7a3a8..4c8b665 100644 --- a/src/ipa/ipa_dummy.cpp +++ b/src/ipa/ipa_dummy.cpp @@ -34,6 +34,7 @@ const struct IPAModuleInfo ipaModuleInfo = { 0, "PipelineHandlerVimc", "Dummy IPA for Vimc", + "LGPL-2.1-or-later", }; IPAInterface *ipaCreate() diff --git a/src/libcamera/ipa_module.cpp b/src/libcamera/ipa_module.cpp index d2e3c36..9cead71 100644 --- a/src/libcamera/ipa_module.cpp +++ b/src/libcamera/ipa_module.cpp @@ -214,6 +214,29 @@ elfLoadSymbol(void *map, size_t soSize, const char *symbol) * * \var IPAModuleInfo::name * \brief The name of the IPA module + * + * \var IPAModuleInfo::license + * \brief License of the IPA module + * + * This license is used to determine whether to force isolation of the IPA in + * a separate process. If the license is "Proprietary", then the IPA will + * be isolated. If the license is open-source, then the IPA will be allowed to + * run without isolation if the user enables it. The license should be an + * SPDX license string. The following licenses are currently available to + * allow the IPA to run unisolated: + * + * - GPL-2.0-only + * - GPL-2.0-or-later + * - GPL-3.0-only + * - GPL-3.0-or-later + * - LGPL-2.1-only + * - LGPL-2.1-or-later + * - LGPL-3.0-only + * - LGPL-3.0-or-later + * + * Any other license will cause the IPA to be run isolated. + * + * \todo Allow user to choose to isolate open source IPAs */ /** diff --git a/test/ipa/ipa_test.cpp b/test/ipa/ipa_test.cpp index bbef069..b9e1bd6 100644 --- a/test/ipa/ipa_test.cpp +++ b/test/ipa/ipa_test.cpp @@ -59,6 +59,7 @@ protected: 0, "PipelineHandlerVimc", "Dummy IPA for Vimc", + "GPL-2.0-or-later", }; count += runTest("src/ipa/ipa_dummy.so", testInfo); From patchwork Thu Jul 11 18:50:41 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Paul Elder X-Patchwork-Id: 1661 Return-Path: Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [213.167.242.64]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id D793860BC8 for ; Thu, 11 Jul 2019 20:51:07 +0200 (CEST) Received: from neptunite.amanokami.net (softbank126163157105.bbtec.net [126.163.157.105]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id 89D8B31C; Thu, 11 Jul 2019 20:51:06 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1562871067; bh=o9wA7F2M8MqSKml05Uk3iGKZlmjeZKKBMDFS0trE3FI=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=qmKUkSjFAD0GkgNSYAivyOyFPPew7cE9C7Eh+QHsXGzb7Ej/7rBj7d1FhoLhZxtwm dxxWxNPCosOhwRKoDdp5eiu2bmWpa009mmVkkDid2rUiHmNa8a03EfFn2EcKEcYwSr ErJSmw/ZlKZDz/seXCEWuV88HTuz9txGyfAtHiwY= From: Paul Elder To: libcamera-devel@lists.libcamera.org Date: Fri, 12 Jul 2019 03:50:41 +0900 Message-Id: <20190711185047.11671-3-paul.elder@ideasonboard.com> X-Mailer: git-send-email 2.20.1 In-Reply-To: <20190711185047.11671-1-paul.elder@ideasonboard.com> References: <20190711185047.11671-1-paul.elder@ideasonboard.com> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v4 2/8] libcamera: ipa_module: add isOpenSource X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Thu, 11 Jul 2019 18:51:08 -0000 Add a method to IPAModule to check if the module is open source. This uses the license field of the member IPAModuleInfo. Signed-off-by: Paul Elder Reviewed-by: Laurent Pinchart --- New in v4 src/libcamera/include/ipa_module.h | 2 ++ src/libcamera/ipa_module.cpp | 23 +++++++++++++++++++++++ 2 files changed, 25 insertions(+) diff --git a/src/libcamera/include/ipa_module.h b/src/libcamera/include/ipa_module.h index b88ae5d..18e9223 100644 --- a/src/libcamera/include/ipa_module.h +++ b/src/libcamera/include/ipa_module.h @@ -35,6 +35,8 @@ public: bool match(PipelineHandler *pipe, uint32_t minVersion, uint32_t maxVersion) const; + bool isOpenSource() const; + private: struct IPAModuleInfo info_; diff --git a/src/libcamera/ipa_module.cpp b/src/libcamera/ipa_module.cpp index 9cead71..788915e 100644 --- a/src/libcamera/ipa_module.cpp +++ b/src/libcamera/ipa_module.cpp @@ -7,6 +7,7 @@ #include "ipa_module.h" +#include #include #include #include @@ -469,4 +470,26 @@ bool IPAModule::match(PipelineHandler *pipe, !strcmp(info_.pipelineName, pipe->name()); } +/** + * \brief Verify if the IPA module is open source + * + * \sa IPAModuleInfo::license + */ +bool IPAModule::isOpenSource() const +{ + static std::vector osLicenses = { + "GPL-2.0-only", + "GPL-2.0-or-later", + "GPL-3.0-only", + "GPL-3.0-or-later", + "LGPL-2.1-only", + "LGPL-2.1-or-later", + "LGPL-3.0-only", + "LGPL-3.0-or-later", + }; + + return std::find(osLicenses.begin(), osLicenses.end(), info_.license) + != osLicenses.end(); +} + } /* namespace libcamera */ From patchwork Thu Jul 11 18:50:42 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Paul Elder X-Patchwork-Id: 1662 Return-Path: Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [IPv6:2001:4b98:dc2:55:216:3eff:fef7:d647]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 0A9D260BC8 for ; Thu, 11 Jul 2019 20:51:10 +0200 (CEST) Received: from neptunite.amanokami.net (softbank126163157105.bbtec.net [126.163.157.105]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id 4435631C; Thu, 11 Jul 2019 20:51:08 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1562871069; bh=gTxU/yV34VSN9mpAeOUb4stPKpO1eKoW6NHHw/ASNM0=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=cshHpWfupvo5jWQwFCXarmzCrvtAUokc5pY9Li50Ksi9BqpCzr1vcXbyF1W63xuGG x6HCZwa/+2OSgx5G610DpHNZ5eeQc5pQNVmFqyMCIf5chU+L/7FATdLGFfe9fr9Uh0 esECQwp+Q9dudKZqr0Rn1RmhZgQG3F7nKL8TCxqU= From: Paul Elder To: libcamera-devel@lists.libcamera.org Date: Fri, 12 Jul 2019 03:50:42 +0900 Message-Id: <20190711185047.11671-4-paul.elder@ideasonboard.com> X-Mailer: git-send-email 2.20.1 In-Reply-To: <20190711185047.11671-1-paul.elder@ideasonboard.com> References: <20190711185047.11671-1-paul.elder@ideasonboard.com> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v4 3/8] libcamera: Add Process and ProcessManager classes X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Thu, 11 Jul 2019 18:51:10 -0000 Add a Process class to abstract a process, and a ProcessManager singleton to monitor and manage the processes. Signed-off-by: Paul Elder Reviewed-by: Laurent Pinchart --- Changes in v4: - rename enum ExitStatus members - use a running_ flag (instead of state_) - fix sigaction registration (on Process construction) - restore old signal handler (on Process destruction) - replace closefrom_except() with closeAllFdsExcept() - unsetenv LIBCAMERA_LOG_FILE on fork (before exec) Changes in v3: - add Process test - move ProcessManager header to process.cpp - make Process final - add a bunch of things for monitoring and signals on process termination New in v2 src/libcamera/include/process.h | 55 +++++ src/libcamera/meson.build | 3 + src/libcamera/process.cpp | 357 ++++++++++++++++++++++++++++++ src/libcamera/process_manager.cpp | 0 test/meson.build | 1 + test/process/meson.build | 12 + test/process/process_test.cpp | 100 +++++++++ 7 files changed, 528 insertions(+) create mode 100644 src/libcamera/include/process.h create mode 100644 src/libcamera/process.cpp create mode 100644 src/libcamera/process_manager.cpp create mode 100644 test/process/meson.build create mode 100644 test/process/process_test.cpp diff --git a/src/libcamera/include/process.h b/src/libcamera/include/process.h new file mode 100644 index 0000000..d322fce --- /dev/null +++ b/src/libcamera/include/process.h @@ -0,0 +1,55 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +/* + * Copyright (C) 2019, Google Inc. + * + * process.h - Process object + */ +#ifndef __LIBCAMERA_PROCESS_H__ +#define __LIBCAMERA_PROCESS_H__ + +#include +#include + +#include + +namespace libcamera { + +class Process final +{ +public: + enum ExitStatus { + NotExited, + NormalExit, + SignalExit, + }; + + Process(); + ~Process(); + + int start(const std::string &path, + const std::vector &args = std::vector(), + const std::vector &fds = std::vector()); + + ExitStatus exitStatus() const { return exitStatus_; } + int exitCode() const { return exitCode_; } + + void kill(); + + Signal finished; + +private: + void closeAllFdsExcept(const std::vector &fds); + int isolate(); + void died(int wstatus); + + pid_t pid_; + bool running_; + enum ExitStatus exitStatus_; + int exitCode_; + + friend class ProcessManager; +}; + +} /* namespace libcamera */ + +#endif /* __LIBCAMERA_PROCESS_H__ */ diff --git a/src/libcamera/meson.build b/src/libcamera/meson.build index eda506b..01565c1 100644 --- a/src/libcamera/meson.build +++ b/src/libcamera/meson.build @@ -21,6 +21,8 @@ libcamera_sources = files([ 'message.cpp', 'object.cpp', 'pipeline_handler.cpp', + 'process.cpp', + 'process_manager.cpp', 'request.cpp', 'signal.cpp', 'stream.cpp', @@ -48,6 +50,7 @@ libcamera_headers = files([ 'include/media_object.h', 'include/message.h', 'include/pipeline_handler.h', + 'include/process.h', 'include/thread.h', 'include/utils.h', 'include/v4l2_device.h', diff --git a/src/libcamera/process.cpp b/src/libcamera/process.cpp new file mode 100644 index 0000000..736d59f --- /dev/null +++ b/src/libcamera/process.cpp @@ -0,0 +1,357 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +/* + * Copyright (C) 2019, Google Inc. + * + * process.cpp - Process object + */ + +#include "process.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "log.h" +#include "utils.h" + +/** + * \file process.h + * \brief Process object + */ + +namespace libcamera { + +LOG_DEFINE_CATEGORY(Process) + +/** + * \class ProcessManager + * \brief Manager of processes + * + * The ProcessManager singleton keeps track of all created Process instances, + * and manages the signal handling involved in terminating processes. + */ +class ProcessManager +{ +public: + void registerProcess(Process *proc); + + static ProcessManager *instance(); + + int writePipe() const; + + const struct sigaction &oldsa() const; + +private: + void sighandler(EventNotifier *notifier); + ProcessManager(); + ~ProcessManager(); + + std::list processes_; + + struct sigaction oldsa_; + EventNotifier *sigEvent_; + int pipe_[2]; +}; + +namespace { + +void sigact(int signal, siginfo_t *info, void *ucontext) +{ + char data = 0; + write(ProcessManager::instance()->writePipe(), &data, sizeof(data)); + + const struct sigaction &oldsa = ProcessManager::instance()->oldsa(); + if (oldsa.sa_flags & SA_SIGINFO) { + oldsa.sa_sigaction(signal, info, ucontext); + } else { + if (oldsa.sa_handler != SIG_IGN && oldsa.sa_handler != SIG_DFL) + oldsa.sa_handler(signal); + } +} + +} /* namespace */ + +void ProcessManager::sighandler(EventNotifier *notifier) +{ + char data; + read(pipe_[0], &data, sizeof(data)); + + for (auto it = processes_.begin(); it != processes_.end(); ) { + Process *process = *it; + + int wstatus; + pid_t pid = waitpid(process->pid_, &wstatus, WNOHANG); + if (process->pid_ != pid) { + ++it; + continue; + } + + it = processes_.erase(it); + process->died(wstatus); + } +} + +/** + * \brief Register process with process manager + * \param[in] proc Process to register + * + * This method registers the \a proc with the process manager. It + * shall be called by the parent process after successfully forking, in + * order to let the parent signal process termination. + */ +void ProcessManager::registerProcess(Process *proc) +{ + processes_.push_back(proc); +} + +ProcessManager::ProcessManager() +{ + sigaction(SIGCHLD, NULL, &oldsa_); + + struct sigaction sa; + memset(&sa, 0, sizeof(sa)); + sa.sa_sigaction = &sigact; + memcpy(&sa.sa_mask, &oldsa_.sa_mask, sizeof(sa.sa_mask)); + sigaddset(&sa.sa_mask, SIGCHLD); + sa.sa_flags = oldsa_.sa_flags | SA_SIGINFO; + + sigaction(SIGCHLD, &sa, NULL); + + pipe2(pipe_, O_CLOEXEC | O_DIRECT | O_NONBLOCK); + sigEvent_ = new EventNotifier(pipe_[0], EventNotifier::Read); + sigEvent_->activated.connect(this, &ProcessManager::sighandler); +} + +ProcessManager::~ProcessManager() +{ + delete sigEvent_; + close(pipe_[0]); + close(pipe_[1]); + sigaction(SIGCHLD, &oldsa_, NULL); +} + +/** + * \brief Retrieve the Process manager instance + * + * The ProcessManager is a singleton and can't be constructed manually. This + * method shall instead be used to retrieve the single global instance of the + * manager. + * + * \return The Process manager instance + */ +ProcessManager *ProcessManager::instance() +{ + static ProcessManager processManager; + return &processManager; +} + +/** + * \brief Retrieve the Process manager's write pipe + * + * This method is meant only to be used by the static signal handler. + * + * \return Pipe for writing + */ +int ProcessManager::writePipe() const +{ + return pipe_[1]; +} + +/** + * \brief Retrive the old signal action data + * + * This method is meant only to be used by the static signal handler. + * + * \return The old signal action data + */ +const struct sigaction &ProcessManager::oldsa() const +{ + return oldsa_; +} + + +/** + * \class Process + * \brief Process object + * + * The Process class models a process, and simplifies spawning new processes + * and monitoring the exiting of a process. + */ + +/** + * \enum Process::ExitStatus + * \brief Exit status of process + * \var Process::NotExited + * The process hasn't exited yet + * \var Process::NormalExit + * The process exited normally, either via exit() or returning from main + * \var Process::SignalExit + * The process was terminated by a signal (this includes crashing) + */ + +Process::Process() + : pid_(-1), running_(false), exitStatus_(NotExited), exitCode_(0) +{ +} + +Process::~Process() +{ + kill(); + /* \todo wait for child process to exit */ +} + +/** + * \brief Fork and exec a process, and close fds + * \param[in] path Path to executable + * \param[in] args Arguments to pass to executable (optional) + * \param[in] fds Vector of file descriptors to keep open (optional) + * + * Fork a process, and exec the executable specified by path. Prior to + * exec'ing, but after forking, all file descriptors except for those + * specified in fds will be closed. + * + * All indexes of args will be incremented by 1 before being fed to exec(), + * so args[0] should not need to be equal to path. + * + * \return zero on successful fork, exec, and closing the file descriptors, + * or a negative error code otherwise + */ +int Process::start(const std::string &path, + const std::vector &args, + const std::vector &fds) +{ + int ret; + + if (running_ == true) + return 0; + + int childPid = fork(); + if (childPid == -1) { + ret = -errno; + LOG(Process, Error) << "Failed to fork: " << strerror(-ret); + return ret; + } else if (childPid) { + pid_ = childPid; + ProcessManager::instance()->registerProcess(this); + + running_ = true; + + return 0; + } else { + if (isolate()) + _exit(EXIT_FAILURE); + + closeAllFdsExcept(fds); + + unsetenv("LIBCAMERA_LOG_FILE"); + + const char **argv = new const char *[args.size() + 2]; + unsigned int len = args.size(); + argv[0] = path.c_str(); + for (unsigned int i = 0; i < len; i++) + argv[i+1] = args[i].c_str(); + argv[len+1] = nullptr; + + execv(path.c_str(), (char **)argv); + + exit(EXIT_FAILURE); + } +} + +void Process::closeAllFdsExcept(const std::vector &fds) +{ + std::vector v(fds); + sort(v.begin(), v.end()); + + DIR *dir = opendir("/proc/self/fd"); + if (!dir) + return; + + int dfd = dirfd(dir); + + struct dirent *ent; + while ((ent = readdir(dir)) != nullptr) { + char *endp; + int fd = strtoul(ent->d_name, &endp, 10); + if (*endp) + continue; + + if (fd >= 0 && fd != dfd && + !std::binary_search(v.begin(), v.end(), fd)) + close(fd); + } + + closedir(dir); +} + +int Process::isolate() +{ + return unshare(CLONE_NEWUSER | CLONE_NEWNET); +} + +/** + * \brief SIGCHLD handler + * \param[in] wstatus The status as output by waitpid() + * + * This method is called when the process associated with Process terminates. + * It emits the Process::finished signal. + */ +void Process::died(int wstatus) +{ + running_ = false; + exitStatus_ = WIFEXITED(wstatus) ? NormalExit : SignalExit; + exitCode_ = exitStatus_ == NormalExit ? WEXITSTATUS(wstatus) : -1; + + finished.emit(this, exitStatus_, exitCode_); +} + +/** + * \fn Process::exitStatus() + * \brief Retrieve the exit status of the process + * + * Return the exit status of the process, that is, whether the process + * has exited via exit() or returning from main, or if the process was + * terminated by a signal. + * + * \sa ExitStatus + * + * \return The process exit status + */ + +/** + * \fn Process::exitCode() + * \brief Retrieve the exit code of the process + * + * This method is only valid if exitStatus() returned NormalExit. + * + * \return Exit code + */ + +/** + * \var Process::finished + * + * Signal that is emitted when the process is confirmed to have terminated. + */ + +/** + * \brief Kill the process + * + * Sends SIGKILL to the process. + */ +void Process::kill() +{ + ::kill(pid_, SIGKILL); +} + +} /* namespace libcamera */ diff --git a/src/libcamera/process_manager.cpp b/src/libcamera/process_manager.cpp new file mode 100644 index 0000000..e69de29 diff --git a/test/meson.build b/test/meson.build index d308ac9..ad1a2f2 100644 --- a/test/meson.build +++ b/test/meson.build @@ -6,6 +6,7 @@ subdir('ipa') subdir('ipc') subdir('media_device') subdir('pipeline') +subdir('process') subdir('stream') subdir('v4l2_subdevice') subdir('v4l2_videodevice') diff --git a/test/process/meson.build b/test/process/meson.build new file mode 100644 index 0000000..c4d83d6 --- /dev/null +++ b/test/process/meson.build @@ -0,0 +1,12 @@ +process_tests = [ + [ 'process_test', 'process_test.cpp' ], +] + +foreach t : process_tests + exe = executable(t[0], t[1], + dependencies : libcamera_dep, + link_with : test_libraries, + include_directories : test_includes_internal) + + test(t[0], exe, suite : 'process', is_parallel : false) +endforeach diff --git a/test/process/process_test.cpp b/test/process/process_test.cpp new file mode 100644 index 0000000..8a7d09f --- /dev/null +++ b/test/process/process_test.cpp @@ -0,0 +1,100 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Copyright (C) 2019, Google Inc. + * + * process_test.cpp - Process test + */ + +#include +#include +#include + +#include +#include +#include + +#include "process.h" +#include "test.h" +#include "utils.h" + +using namespace std; +using namespace libcamera; + +class ProcessTestChild +{ +public: + int run(int status) + { + usleep(50000); + + return status; + } +}; + +class ProcessTest : public Test +{ +public: + ProcessTest() + { + } + +protected: + int run() + { + EventDispatcher *dispatcher = CameraManager::instance()->eventDispatcher(); + Timer timeout; + + int exitCode = 42; + vector args; + args.push_back(to_string(exitCode)); + int ret = proc_.start("/proc/self/exe", args); + if (ret) { + cerr << "failed to fork" << endl; + return TestFail; + } + proc_.finished.connect(this, &ProcessTest::procFinished); + + timeout.start(80); + while (timeout.isRunning()) + dispatcher->processEvents(); + + if (exitStatus_ != Process::NormalExit) { + cerr << "process did not exit normally" << endl; + return TestFail; + } + + if (exitCode != exitCode_) { + cerr << "exit code should be " << exitCode + << ", actual is " << exitCode_ << endl; + return TestFail; + } + + return TestPass; + } + +private: + void procFinished(Process *proc, enum Process::ExitStatus exitStatus, int exitCode) + { + exitStatus_ = exitStatus; + exitCode_ = exitCode; + } + + Process proc_; + enum Process::ExitStatus exitStatus_; + int exitCode_; +}; + +/* + * Can't use TEST_REGISTER() as single binary needs to act as both + * parent and child processes. + */ +int main(int argc, char **argv) +{ + if (argc == 2) { + int status = std::stoi(argv[1]); + ProcessTestChild child; + return child.run(status); + } + + return ProcessTest().execute(); +} From patchwork Thu Jul 11 18:50:43 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Paul Elder X-Patchwork-Id: 1663 Return-Path: Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [213.167.242.64]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 1AF0560BC8 for ; Thu, 11 Jul 2019 20:51:12 +0200 (CEST) Received: from neptunite.amanokami.net (softbank126163157105.bbtec.net [126.163.157.105]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id 6A0AE31C; Thu, 11 Jul 2019 20:51:10 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1562871071; bh=cJtQ6cXdD94Z46S6fchGmbwhCE3t9ZIDKKM39prS3VI=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=e6D2NEbCN3HIEGro9AGF0EjYVpRmMfrhUZk/aLyWJzS6pVpYsxLqUQSuZ3PLU+AmW 3atxpSTBMDo6+BCTVNRy+PGsxlNf/LOeyDygxltFuhOg//RmrfvPbat0aHkt+vgRqV CsH/i2TMJdCvEJ/3jTNbKscBr0jfftok0ATGC4HY= From: Paul Elder To: libcamera-devel@lists.libcamera.org Date: Fri, 12 Jul 2019 03:50:43 +0900 Message-Id: <20190711185047.11671-5-paul.elder@ideasonboard.com> X-Mailer: git-send-email 2.20.1 In-Reply-To: <20190711185047.11671-1-paul.elder@ideasonboard.com> References: <20190711185047.11671-1-paul.elder@ideasonboard.com> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v4 4/8] libcamera: add IPA proxy X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Thu, 11 Jul 2019 18:51:12 -0000 Add an IPAProxy class whose implementations will act as a proxy between a pipeline handler and an isolated IPA interface. Also add an IPAProxyFactory that will construct the IPAProxy implementations as necessary. Update Doxygen to ignore the directory where IPAProxy implementations will reside. Signed-off-by: Paul Elder Reviewed-by: Laurent Pinchart --- No major change in v4 Changes in v3: - renamed Proxy and ProxyFactory to IPAProxy and IPAProxyFactory - moved proxy workers to proxy/worker/ (from proxy_worker/) New in v2 - replaces shims from v1 - build into libcamera, hence the register macro (similar to what PipelineHandler uses) - no longer builds separate .so Documentation/Doxyfile.in | 3 +- src/libcamera/include/ipa_proxy.h | 66 ++++++++++ src/libcamera/ipa_proxy.cpp | 204 ++++++++++++++++++++++++++++++ src/libcamera/meson.build | 6 + test/libtest/test.cpp | 4 + 5 files changed, 282 insertions(+), 1 deletion(-) create mode 100644 src/libcamera/include/ipa_proxy.h create mode 100644 src/libcamera/ipa_proxy.cpp diff --git a/Documentation/Doxyfile.in b/Documentation/Doxyfile.in index cad85ff..3d94623 100644 --- a/Documentation/Doxyfile.in +++ b/Documentation/Doxyfile.in @@ -837,7 +837,8 @@ EXCLUDE = @TOP_SRCDIR@/src/libcamera/device_enumerator_sysfs.cpp @TOP_SRCDIR@/src/libcamera/device_enumerator_udev.cpp \ @TOP_SRCDIR@/src/libcamera/include/device_enumerator_sysfs.h \ @TOP_SRCDIR@/src/libcamera/include/device_enumerator_udev.h \ - @TOP_SRCDIR@/src/libcamera/pipeline/ + @TOP_SRCDIR@/src/libcamera/pipeline/ \ + @TOP_SRCDIR@/src/libcamera/proxy/ # The EXCLUDE_SYMLINKS tag can be used to select whether or not files or # directories that are symbolic links (a Unix file system feature) are excluded diff --git a/src/libcamera/include/ipa_proxy.h b/src/libcamera/include/ipa_proxy.h new file mode 100644 index 0000000..ac57699 --- /dev/null +++ b/src/libcamera/include/ipa_proxy.h @@ -0,0 +1,66 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +/* + * Copyright (C) 2019, Google Inc. + * + * ipa_proxy.h - Image Processing Algorithm proxy + */ +#ifndef __LIBCAMERA_IPA_PROXY_H__ +#define __LIBCAMERA_IPA_PROXY_H__ + +#include +#include +#include + +#include + +#include "ipa_module.h" +#include "utils.h" + +namespace libcamera { + +class IPAProxy : public IPAInterface +{ +public: + IPAProxy(); + ~IPAProxy(); + + bool isValid() const { return valid_; } + +protected: + std::string resolvePath(const std::string &file) const; + + bool valid_; +}; + +class IPAProxyFactory +{ +public: + IPAProxyFactory(const char *name); + virtual ~IPAProxyFactory(){}; + + virtual std::unique_ptr create(IPAModule *ipam) = 0; + + const std::string &name() const { return name_; } + + static void registerType(IPAProxyFactory *factory); + static std::vector &factories(); + +private: + std::string name_; +}; + +#define REGISTER_IPA_PROXY(proxy) \ +class proxy##Factory final : public IPAProxyFactory \ +{ \ +public: \ + proxy##Factory() : IPAProxyFactory(#proxy) {} \ + std::unique_ptr create(IPAModule *ipam) \ + { \ + return utils::make_unique(ipam); \ + } \ +}; \ +static proxy##Factory global_##proxy##Factory; + +} /* namespace libcamera */ + +#endif /* __LIBCAMERA_IPA_PROXY_H__ */ diff --git a/src/libcamera/ipa_proxy.cpp b/src/libcamera/ipa_proxy.cpp new file mode 100644 index 0000000..5a3d2f1 --- /dev/null +++ b/src/libcamera/ipa_proxy.cpp @@ -0,0 +1,204 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +/* + * Copyright (C) 2019, Google Inc. + * + * ipa_proxy.cpp - Image Processing Algorithm proxy + */ + +#include "ipa_proxy.h" + +#include +#include + +#include "log.h" +#include "utils.h" + +#include + +/** + * \file ipa_proxy.h + * \brief IPA Proxy + */ + +namespace libcamera { + +LOG_DEFINE_CATEGORY(IPAProxy) + +/** + * \class IPAProxy + * \brief IPA Proxy + * + * Isolate IPA into separate process. + * + * Every subclass of proxy shall be registered with libcamera using + * the REGISTER_IPA_PROXY() macro. + */ + +/** + * \brief Construct an IPAProxy instance + * + * IPAProxy instances shall be constructed through the IPAProxyFactory::create() + * method implemented by the respective factories. + */ +IPAProxy::IPAProxy() + : valid_(false) +{ +} + +IPAProxy::~IPAProxy() +{ +} + +/** + * \fn IPAProxy::isValid() + * \brief Check if the IPAProxy instance is valid + * + * An IPAProxy instance is valid if the IPA interface is successfully created in + * isolation, and IPC is successfully set up. + * + * \return True if the IPAProxy is valid, false otherwise + */ + +/** + * \brief Find a valid full path for a proxy worker for a given executable name + * \param[in] file File name of proxy worker executable + * + * A proxy worker's executable could be found in either the global installation + * directory, or in the paths specified by the environment variable + * LIBCAMERA_IPA_PROXY_PATH. This method checks the global install directory + * first, then LIBCAMERA_IPA_PROXY_PATH in order, and returns the full path to + * the proxy worker executable that is specified by file. The proxy worker + * executable shall have exec permission. + * + * \return The full path to the proxy worker executable, or an empty string if + * no valid executable path + */ +std::string IPAProxy::resolvePath(const std::string &file) const +{ + /* Try finding the exec target from the install directory first */ + std::string proxyFile = "/" + file; + std::string proxyPath = std::string(IPA_PROXY_DIR) + proxyFile; + if (!access(proxyPath.c_str(), X_OK)) + return proxyPath; + + /* No exec target in install directory; check env variable. */ + const char *execPaths = utils::secure_getenv("LIBCAMERA_IPA_PROXY_PATH"); + while (execPaths) { + const char *delim = strchrnul(execPaths, ':'); + size_t count = delim - execPaths; + + if (count) { + std::string proxyPath(execPaths, count); + proxyPath += proxyFile; + if (!access(proxyPath.c_str(), X_OK)) + return proxyPath; + } + + if (*delim == '\0') + break; + + execPaths += count + 1; + } + + return std::string(); +} + +/** + * \var IPAProxy::valid_ + * \brief Flag to indicate if the IPAProxy instance is valid + * + * A IPAProxy instance is valid if the IPA interface is successfully created in + * isolation, and IPC is successfully set up. + * + * This flag can be read via IPAProxy::isValid(). + * + * Implementations of the IPAProxy class should set this flag upon successful + * construction. + */ + +/** + * \class IPAProxyFactory + * \brief Registration of IPAProxy classes and creation of instances + * + * To facilitate discovery and instantiation of IPAProxy classes, the + * IPAProxyFactory class maintains a registry of IPAProxy classes. Each + * IPAProxy subclass shall register itself using the REGISTER_IPA_PROXY() + * macro, which will create a corresponding instance of a IPAProxyFactory + * subclass and register it with the static list of factories. + */ + +/** + * \brief Construct a IPAProxy factory + * \param[in] name Name of the IPAProxy class + * + * Creating an instance of the factory registers is with the global list of + * factories, accessible through the factories() function. + * + * The factory \a name is used for debugging and IPAProxy matching purposes + * and shall be unique. + */ +IPAProxyFactory::IPAProxyFactory(const char *name) + : name_(name) +{ + registerType(this); +} + +/** + * \fn IPAProxyFactory::create() + * \brief Create an instance of the IPAProxy corresponding to the factory + * \param[in] ipam The IPA module + * + * This virtual function is implemented by the REGISTER_IPA_PROXY() macro. + * It creates a IPAProxy instance that isolates an IPA interface designated + * by the IPA module \a ipam. + * + * \return A pointer to a newly constructed instance of the IPAProxy subclass + * corresponding to the factory + */ + +/** + * \fn IPAProxyFactory::name() + * \brief Retrieve the factory name + * \return The factory name + */ + +/** + * \brief Add a IPAProxy class to the registry + * \param[in] factory Factory to use to construct the IPAProxy + * + * The caller is responsible to guarantee the uniqueness of the IPAProxy name. + */ +void IPAProxyFactory::registerType(IPAProxyFactory *factory) +{ + std::vector &factories = IPAProxyFactory::factories(); + + factories.push_back(factory); + + LOG(IPAProxy, Debug) + << "Registered proxy \"" << factory->name() << "\""; +} + +/** + * \brief Retrieve the list of all IPAProxy factories + * + * The static factories map is defined inside the function to ensure it gets + * initialized on first use, without any dependency on link order. + * + * \return The list of pipeline handler factories + */ +std::vector &IPAProxyFactory::factories() +{ + static std::vector factories; + return factories; +} + +/** + * \def REGISTER_IPA_PROXY + * \brief Register a IPAProxy with the IPAProxy factory + * \param[in] proxy Class name of IPAProxy derived class to register + * + * Register a proxy subclass with the factory and make it available to + * isolate IPA modules. + */ + +} /* namespace libcamera */ diff --git a/src/libcamera/meson.build b/src/libcamera/meson.build index 01565c1..3e86edb 100644 --- a/src/libcamera/meson.build +++ b/src/libcamera/meson.build @@ -14,6 +14,7 @@ libcamera_sources = files([ 'ipa_interface.cpp', 'ipa_manager.cpp', 'ipa_module.cpp', + 'ipa_proxy.cpp', 'ipc_unixsocket.cpp', 'log.cpp', 'media_device.cpp', @@ -44,6 +45,7 @@ libcamera_headers = files([ 'include/formats.h', 'include/ipa_manager.h', 'include/ipa_module.h', + 'include/ipa_proxy.h', 'include/ipc_unixsocket.h', 'include/log.h', 'include/media_device.h', @@ -67,6 +69,10 @@ includes = [ subdir('pipeline') +proxy_install_dir = join_paths(get_option('libdir'), 'libcamera', 'proxy') +config_h.set('IPA_PROXY_DIR', + '"' + join_paths(get_option('prefix'), proxy_install_dir) + '"') + libudev = dependency('libudev', required : false) if libudev.found() diff --git a/test/libtest/test.cpp b/test/libtest/test.cpp index b119cf1..333d216 100644 --- a/test/libtest/test.cpp +++ b/test/libtest/test.cpp @@ -25,6 +25,10 @@ int Test::execute() if (ret) return errno; + ret = setenv("LIBCAMERA_IPA_PROXY_PATH", "src/libcamera/proxy/worker", 1); + if (ret) + return errno; + ret = init(); if (ret) return ret; From patchwork Thu Jul 11 18:50:44 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Paul Elder X-Patchwork-Id: 1664 Return-Path: Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [213.167.242.64]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 1B97061573 for ; Thu, 11 Jul 2019 20:51:14 +0200 (CEST) Received: from neptunite.amanokami.net (softbank126163157105.bbtec.net [126.163.157.105]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id 6DADD31C; Thu, 11 Jul 2019 20:51:12 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1562871073; bh=n3tF2OXDrku7quHEX0f6Ix4vYB++A/mUEq2f9nkpqfg=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=F5KmxlBmOXpTIrWJpzC35u+y/AjMBRwY2Jt6loIzivui7cXY7fJoeXUGdbRDRNgl+ 5gAg5hfh3qzSIskCrwDFU5MHAb9KMw30AcgWQVrzdi4bJfHco8u6KNoNFrLXyLCbcP Cu/DyNM9/BQyeRD18WNbeksQ6ZLqqhtJqH6f1alc= From: Paul Elder To: libcamera-devel@lists.libcamera.org Date: Fri, 12 Jul 2019 03:50:44 +0900 Message-Id: <20190711185047.11671-6-paul.elder@ideasonboard.com> X-Mailer: git-send-email 2.20.1 In-Reply-To: <20190711185047.11671-1-paul.elder@ideasonboard.com> References: <20190711185047.11671-1-paul.elder@ideasonboard.com> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v4 5/8] libcamera: proxy: add default linux IPA proxy X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Thu, 11 Jul 2019 18:51:14 -0000 Add a skeletal default linux IPA proxy. It currently lacks the IPA proxy protocol itself. Signed-off-by: Paul Elder Reviewed-by: Laurent Pinchart --- This patch depends on "libcamera: logging: add logging API for applications" Changes in v4: - use logging API to set the log file in the proxy worker Changes in v3: - better logging (both main proxy and proxy worker) - renamed ProxyLinuxDefault to IPAProxyLinux - initialize listeners for IPC New in v2 - replaces the dummy/linux default shim src/libcamera/meson.build | 7 +- src/libcamera/proxy/ipa_proxy_linux.cpp | 96 +++++++++++++++++++ src/libcamera/proxy/meson.build | 3 + .../proxy/worker/ipa_proxy_linux_worker.cpp | 86 +++++++++++++++++ src/libcamera/proxy/worker/meson.build | 16 ++++ 5 files changed, 204 insertions(+), 4 deletions(-) create mode 100644 src/libcamera/proxy/ipa_proxy_linux.cpp create mode 100644 src/libcamera/proxy/meson.build create mode 100644 src/libcamera/proxy/worker/ipa_proxy_linux_worker.cpp create mode 100644 src/libcamera/proxy/worker/meson.build diff --git a/src/libcamera/meson.build b/src/libcamera/meson.build index 3e86edb..6a9d270 100644 --- a/src/libcamera/meson.build +++ b/src/libcamera/meson.build @@ -68,10 +68,7 @@ includes = [ ] subdir('pipeline') - -proxy_install_dir = join_paths(get_option('libdir'), 'libcamera', 'proxy') -config_h.set('IPA_PROXY_DIR', - '"' + join_paths(get_option('prefix'), proxy_install_dir) + '"') +subdir('proxy') libudev = dependency('libudev', required : false) @@ -116,3 +113,5 @@ libcamera = shared_library('camera', libcamera_dep = declare_dependency(sources : [libcamera_api, libcamera_h], include_directories : libcamera_includes, link_with : libcamera) + +subdir('proxy/worker') diff --git a/src/libcamera/proxy/ipa_proxy_linux.cpp b/src/libcamera/proxy/ipa_proxy_linux.cpp new file mode 100644 index 0000000..2b3f187 --- /dev/null +++ b/src/libcamera/proxy/ipa_proxy_linux.cpp @@ -0,0 +1,96 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +/* + * Copyright (C) 2019, Google Inc. + * + * ipa_proxy_linux.cpp - Default Image Processing Algorithm proxy for Linux + */ + +#include + +#include +#include + +#include "ipa_module.h" +#include "ipa_proxy.h" +#include "ipc_unixsocket.h" +#include "log.h" +#include "process.h" + +namespace libcamera { + +LOG_DECLARE_CATEGORY(IPAProxy) + +class IPAProxyLinux : public IPAProxy +{ +public: + IPAProxyLinux(IPAModule *ipam); + ~IPAProxyLinux(); + + int init(); + +private: + void readyRead(IPCUnixSocket *ipc); + + Process *proc_; + + IPCUnixSocket *socket_; +}; + +int IPAProxyLinux::init() +{ + LOG(IPAProxy, Debug) << "initializing IPA via dummy proxy!"; + + return 0; +} + +IPAProxyLinux::IPAProxyLinux(IPAModule *ipam) +{ + LOG(IPAProxy, Debug) + << "initializing dummy proxy: loading IPA from " + << ipam->path(); + + std::vector fds; + std::vector args; + args.push_back(ipam->path()); + const std::string path = resolvePath("ipa_proxy_linux"); + if (path.empty()) { + LOG(IPAProxy, Error) + << "Failed to get proxy worker path"; + return; + } + + socket_ = new IPCUnixSocket(); + int fd = socket_->create(); + if (fd < 0) { + LOG(IPAProxy, Error) + << "Failed to create socket"; + return; + } + socket_->readyRead.connect(this, &IPAProxyLinux::readyRead); + args.push_back(std::to_string(fd)); + fds.push_back(fd); + + proc_ = new Process(); + int ret = proc_->start(path, args, fds); + if (ret) { + LOG(IPAProxy, Error) + << "Failed to start IPAProxyLinux worker process"; + return; + } + + valid_ = true; +} + +IPAProxyLinux::~IPAProxyLinux() +{ + delete proc_; + delete socket_; +} + +void IPAProxyLinux::readyRead(IPCUnixSocket *ipc) +{ +} + +REGISTER_IPA_PROXY(IPAProxyLinux) + +}; /* namespace libcamera */ diff --git a/src/libcamera/proxy/meson.build b/src/libcamera/proxy/meson.build new file mode 100644 index 0000000..efc1132 --- /dev/null +++ b/src/libcamera/proxy/meson.build @@ -0,0 +1,3 @@ +libcamera_sources += files([ + 'ipa_proxy_linux.cpp', +]) diff --git a/src/libcamera/proxy/worker/ipa_proxy_linux_worker.cpp b/src/libcamera/proxy/worker/ipa_proxy_linux_worker.cpp new file mode 100644 index 0000000..8b7aa74 --- /dev/null +++ b/src/libcamera/proxy/worker/ipa_proxy_linux_worker.cpp @@ -0,0 +1,86 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Copyright (C) 2019, Google Inc. + * + * ipa_proxy_linux_worker.cpp - Default Image Processing Algorithm proxy worker for Linux + */ + +#include +#include +#include + +#include +#include +#include +#include + +#include "ipa_module.h" +#include "ipc_unixsocket.h" +#include "log.h" +#include "utils.h" + +using namespace libcamera; + +LOG_DEFINE_CATEGORY(IPAProxyLinuxWorker) + +void readyRead(IPCUnixSocket *ipc) +{ + IPCUnixSocket::Payload message; + int ret; + + ret = ipc->receive(&message); + if (ret) { + LOG(IPAProxyLinuxWorker, Error) + << "Receive message failed: " << ret; + return; + } + + LOG(IPAProxyLinuxWorker, Debug) << "Received a message!"; +} + +int main(int argc, char **argv) +{ + std::string logPath = "/tmp/libcamera.process." + + std::to_string(getpid()) + ".log"; + logSetFile(logPath.c_str()); + + if (argc < 3) { + LOG(IPAProxyLinuxWorker, Debug) + << "Tried to start worker with no args"; + return EXIT_FAILURE; + } + + int fd = std::stoi(argv[2]); + LOG(IPAProxyLinuxWorker, Debug) + << "Starting worker for IPA module " << argv[1] + << " with IPC fd = " << fd; + + std::unique_ptr ipam = utils::make_unique(argv[1]); + if (!ipam->isValid() || !ipam->load()) { + LOG(IPAProxyLinuxWorker, Error) + << "IPAModule " << argv[1] << " should be valid but isn't"; + return EXIT_FAILURE; + } + + IPCUnixSocket socket; + if (socket.bind(fd) < 0) { + LOG(IPAProxyLinuxWorker, Error) << "IPC socket binding failed"; + return EXIT_FAILURE; + } + socket.readyRead.connect(&readyRead); + + std::unique_ptr ipa = ipam->createInstance(); + if (!ipa) { + LOG(IPAProxyLinuxWorker, Error) << "Failed to create IPA interface"; + return EXIT_FAILURE; + } + + LOG(IPAProxyLinuxWorker, Debug) << "Proxy worker successfully started"; + + /* \todo upgrade listening loop */ + EventDispatcher *dispatcher = CameraManager::instance()->eventDispatcher(); + while (1) + dispatcher->processEvents(); + + return 0; +} diff --git a/src/libcamera/proxy/worker/meson.build b/src/libcamera/proxy/worker/meson.build new file mode 100644 index 0000000..839156f --- /dev/null +++ b/src/libcamera/proxy/worker/meson.build @@ -0,0 +1,16 @@ +ipa_proxy_sources = [ + ['ipa_proxy_linux', 'ipa_proxy_linux_worker.cpp'] +] + +proxy_install_dir = join_paths(get_option('libexecdir'), 'libcamera') + +foreach t : ipa_proxy_sources + proxy = executable(t[0], t[1], + include_directories : libcamera_internal_includes, + install : true, + install_dir : proxy_install_dir, + dependencies : libcamera_dep) +endforeach + +config_h.set('IPA_PROXY_DIR', + '"' + join_paths(get_option('prefix'), proxy_install_dir) + '"') From patchwork Thu Jul 11 18:50:45 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Paul Elder X-Patchwork-Id: 1665 Return-Path: Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [IPv6:2001:4b98:dc2:55:216:3eff:fef7:d647]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id CCE8A6157A for ; Thu, 11 Jul 2019 20:51:15 +0200 (CEST) Received: from neptunite.amanokami.net (softbank126163157105.bbtec.net [126.163.157.105]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id 701C531C; Thu, 11 Jul 2019 20:51:14 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1562871075; bh=asMxJuYS3eRmMn+bPArvHQyqlmibUefl73Gg935Uxzw=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=eyRvtw8Az4XNU8j95Lqci5JhReIkrVv+rS5m7qv0jeXXadQanx3DTxrnpdXsY66tf wwnPQTmyEGrx1vqGnkZrJoN742m42fCr1JW6tGYM99R3kjN20gTPGZvSndbCGO4WQX /bayCd/TCEmgU8IsAn2J0FnkEsjYDPXo3PeVu9OU= From: Paul Elder To: libcamera-devel@lists.libcamera.org Date: Fri, 12 Jul 2019 03:50:45 +0900 Message-Id: <20190711185047.11671-7-paul.elder@ideasonboard.com> X-Mailer: git-send-email 2.20.1 In-Reply-To: <20190711185047.11671-1-paul.elder@ideasonboard.com> References: <20190711185047.11671-1-paul.elder@ideasonboard.com> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v4 6/8] libcamera: ipa_manager: use proxy X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Thu, 11 Jul 2019 18:51:16 -0000 Make IPAManager isolate an IPA in a Proxy if the IPA's license is not open source, before returning the IPA to the caller. For now, only use the default Linux IPA proxy, and only LGPL 2.1+ is considered open source. Signed-off-by: Paul Elder Reviewed-by: Laurent Pinchart --- Changes in v4: - move IPAModule open source verification to IPAModule::isOpenSource() Changes in v3: - license checking is done with SPDX license strings, and only LGPL 2.1+ is accepted for now New in v2 - replaces adding shims - since Proxies are not external shared objects like the shims in v1 were, there is no longer a list of shims that is treated like IPAModules - instead the matching is done by searching the list of proxy factories src/libcamera/ipa_manager.cpp | 34 ++++++++++++++++++++++++++++++++-- 1 file changed, 32 insertions(+), 2 deletions(-) diff --git a/src/libcamera/ipa_manager.cpp b/src/libcamera/ipa_manager.cpp index 532b77d..4276d99 100644 --- a/src/libcamera/ipa_manager.cpp +++ b/src/libcamera/ipa_manager.cpp @@ -12,6 +12,7 @@ #include #include "ipa_module.h" +#include "ipa_proxy.h" #include "log.h" #include "pipeline_handler.h" #include "utils.h" @@ -129,7 +130,7 @@ int IPAManager::addDir(const char *libDir) * \param[in] maxVersion Maximum acceptable version of IPA module * * \return A newly created IPA interface, or nullptr if no matching - * IPA module is found + * IPA module is found or if the IPA interface fails to initialize */ std::unique_ptr IPAManager::createIPA(PipelineHandler *pipe, uint32_t maxVersion, @@ -144,7 +145,36 @@ std::unique_ptr IPAManager::createIPA(PipelineHandler *pipe, } } - if (!m || !m->load()) + if (!m) + return nullptr; + + if (!m->isOpenSource()) { + IPAProxyFactory *pf = nullptr; + std::vector &factories = IPAProxyFactory::factories(); + + for (IPAProxyFactory *factory : factories) { + /* TODO: Better matching */ + if (!strcmp(factory->name().c_str(), "IPAProxyLinux")) { + pf = factory; + break; + } + } + + if (!pf) { + LOG(IPAManager, Error) << "Failed to get proxy factory"; + return nullptr; + } + + std::unique_ptr proxy = pf->create(m); + if (!proxy->isValid()) { + LOG(IPAManager, Error) << "Failed to load proxy"; + return nullptr; + } + + return proxy; + } + + if (!m->load()) return nullptr; return m->createInstance(); From patchwork Thu Jul 11 18:50:46 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Paul Elder X-Patchwork-Id: 1666 Return-Path: Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [IPv6:2001:4b98:dc2:55:216:3eff:fef7:d647]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id D36EC60BC8 for ; Thu, 11 Jul 2019 20:51:17 +0200 (CEST) Received: from neptunite.amanokami.net (softbank126163157105.bbtec.net [126.163.157.105]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id 3093B567; Thu, 11 Jul 2019 20:51:15 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1562871077; bh=zPr2BG2iryhoLFb5juvcqAuwnozN5QutfEsJbQEWDEI=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=mY2NDJkZyDZhxKGbKiyrps5tBRGOCSnfKvH00nRHjUUbqoIt4j8RkFPBN6x9LGrEO wgEUf/BKXtbmLC4kLTW0XoOrUm6lO+c5nhuhJWQetBS3gZvXs4vqMcQP+aXVQwkF18 337L9oDxmsiGTjSlSVLBqhrudY/Mu7LjzmGrG+Jg= From: Paul Elder To: libcamera-devel@lists.libcamera.org Date: Fri, 12 Jul 2019 03:50:46 +0900 Message-Id: <20190711185047.11671-8-paul.elder@ideasonboard.com> X-Mailer: git-send-email 2.20.1 In-Reply-To: <20190711185047.11671-1-paul.elder@ideasonboard.com> References: <20190711185047.11671-1-paul.elder@ideasonboard.com> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v4 7/8] libcamera: ipa: add dummy IPA that needs to be isolated X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Thu, 11 Jul 2019 18:51:18 -0000 Add a dummy IPA that needs to be isolated. Signed-off-by: Paul Elder Reviewed-by: Laurent Pinchart --- No major change in v4 Changes in v3: - fix header Changes in v2: - ipaModuleInfo contains license rather than "please isolate me" src/ipa/ipa_dummy_isolate.cpp | 47 +++++++++++++++++++++++++++++++++++ 1 file changed, 47 insertions(+) create mode 100644 src/ipa/ipa_dummy_isolate.cpp diff --git a/src/ipa/ipa_dummy_isolate.cpp b/src/ipa/ipa_dummy_isolate.cpp new file mode 100644 index 0000000..24434e8 --- /dev/null +++ b/src/ipa/ipa_dummy_isolate.cpp @@ -0,0 +1,47 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +/* + * Copyright (C) 2019, Google Inc. + * + * ipa_dummy_isolate.cpp - Dummy Image Processing Algorithm module that needs + * to be isolated + */ + +#include + +#include +#include + +namespace libcamera { + +class IPADummyIsolate : public IPAInterface +{ +public: + int init(); +}; + +int IPADummyIsolate::init() +{ + std::cout << "initializing isolated dummy IPA!" << std::endl; + return 0; +} + +/* + * External IPA module interface + */ + +extern "C" { +const struct IPAModuleInfo ipaModuleInfo = { + IPA_MODULE_API_VERSION, + 0, + "PipelineHandlerVimc", + "Dummy IPA for Vimc that needs to be isolated", + "Proprietary", +}; + +IPAInterface *ipaCreate() +{ + return new IPADummyIsolate(); +} +}; + +}; /* namespace libcamera */ From patchwork Thu Jul 11 18:50:47 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Paul Elder X-Patchwork-Id: 1667 Return-Path: Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [IPv6:2001:4b98:dc2:55:216:3eff:fef7:d647]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id C797760E41 for ; Thu, 11 Jul 2019 20:51:19 +0200 (CEST) Received: from neptunite.amanokami.net (softbank126163157105.bbtec.net [126.163.157.105]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id 3309F31C; Thu, 11 Jul 2019 20:51:17 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1562871079; bh=7LGBKxGHG5K+NMFdwRTFe496kSe/GafynRkcoCGVGJ4=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=UfEWCnoTNlyRi7iTzbN2v5Kf60gcfLZ9Tpl7tLAk5WUsMCc1KBXYrOUpQ/OKRwsbP OXRNNr4AWcokmUJdKRsiWDal2MnsrREmuQmQ8u0eea8/mRuzp3UrT/IWUZkyheHrNs 4+z0ERgNs6/EPkmDySuOe7SpwS4apAuhby8SJ3o4= From: Paul Elder To: libcamera-devel@lists.libcamera.org Date: Fri, 12 Jul 2019 03:50:47 +0900 Message-Id: <20190711185047.11671-9-paul.elder@ideasonboard.com> X-Mailer: git-send-email 2.20.1 In-Reply-To: <20190711185047.11671-1-paul.elder@ideasonboard.com> References: <20190711185047.11671-1-paul.elder@ideasonboard.com> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v4 8/8] libcamera: ipa: meson: build dummy IPA that needs isolation X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Thu, 11 Jul 2019 18:51:19 -0000 Add the dummy IPA that needs isolation to meson. At the same time, clean up the IPA meson to facilitate adding more IPAs. Signed-off-by: Paul Elder Reviewed-by: Laurent Pinchart --- No change in v4 Changes in v3: - remove sub install directory for IPAs Changes in v2: - make a sub install directory for IPAs, to keep them separate from the proxies - remove shim compilation src/ipa/meson.build | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/src/ipa/meson.build b/src/ipa/meson.build index 3c33a37..2b9863b 100644 --- a/src/ipa/meson.build +++ b/src/ipa/meson.build @@ -1,15 +1,18 @@ -ipa_dummy_sources = files([ - 'ipa_dummy.cpp', -]) +ipa_dummy_sources = [ + ['ipa_dummy', 'ipa_dummy.cpp'], + ['ipa_dummy_isolate', 'ipa_dummy_isolate.cpp'], +] ipa_install_dir = join_paths(get_option('libdir'), 'libcamera') -ipa_dummy = shared_library('ipa_dummy', - ipa_dummy_sources, - name_prefix : '', - include_directories : libcamera_includes, - install : true, - install_dir : ipa_install_dir) +foreach t : ipa_dummy_sources + ipa = shared_module(t[0], + t[1], + name_prefix : '', + include_directories : libcamera_includes, + install : true, + install_dir : ipa_install_dir) +endforeach config_h.set('IPA_MODULE_DIR', '"' + join_paths(get_option('prefix'), ipa_install_dir) + '"')