From patchwork Wed Jul 3 08:00:02 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Paul Elder X-Patchwork-Id: 1590 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 A317061571 for ; Wed, 3 Jul 2019 10:00:27 +0200 (CEST) Received: from neptunite.flets-east.jp (p1871204-ipngn14001hodogaya.kanagawa.ocn.ne.jp [153.220.127.204]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id E92C32F0; Wed, 3 Jul 2019 10:00:25 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1562140827; bh=XM6yziVBkZ7Pax3Ys1Ef0sjD9obSjnwdVsQ3d7DkznU=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=RohyaIp1jWZCHniU6MKgjVi9mtOYilE4vZ22sOh98OLucDIOSBfcxEqemrvOR0CEj U+dQHsAoRm16TixSzeU1TjFfxBHF6LBkOX6IeP1rTBkO+XJMISkbSJUwYdyupygrGB usS3CLki3DbdMUVxW5pWb5VcnnwdPJFry2vLx7as= From: Paul Elder To: libcamera-devel@lists.libcamera.org Date: Wed, 3 Jul 2019 17:00:02 +0900 Message-Id: <20190703080007.21376-3-paul.elder@ideasonboard.com> X-Mailer: git-send-email 2.20.1 In-Reply-To: <20190703080007.21376-1-paul.elder@ideasonboard.com> References: <20190703080007.21376-1-paul.elder@ideasonboard.com> MIME-Version: 1.0 Subject: [libcamera-devel] [RFC PATCH v2 2/7] libcamera: process, process manager: create process and manager 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: Wed, 03 Jul 2019 08:00:27 -0000 Add a Process class to abstract a process, and a ProcessManager singleton to monitor and manage the processes. Signed-off-by: Paul Elder --- New in v2 src/libcamera/include/process.h | 35 ++++++ src/libcamera/include/process_manager.h | 40 +++++++ src/libcamera/meson.build | 4 + src/libcamera/process.cpp | 140 ++++++++++++++++++++++++ src/libcamera/process_manager.cpp | 104 ++++++++++++++++++ 5 files changed, 323 insertions(+) create mode 100644 src/libcamera/include/process.h create mode 100644 src/libcamera/include/process_manager.h create mode 100644 src/libcamera/process.cpp create mode 100644 src/libcamera/process_manager.cpp diff --git a/src/libcamera/include/process.h b/src/libcamera/include/process.h new file mode 100644 index 0000000..85c0163 --- /dev/null +++ b/src/libcamera/include/process.h @@ -0,0 +1,35 @@ +/* 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 + +namespace libcamera { + +class Process +{ +public: + Process(); + virtual ~Process(); + + int exec(const std::string &path, const std::vector &args, const std::vector &fds); + +private: + pid_t pid_; + bool execed_; + + /* TODO better prototype, and implementation; emit finished signal */ + virtual void sigchldHandler() { }; + + friend class ProcessManager; +}; + +} /* namespace libcamera */ + +#endif /* __LIBCAMERA_PROCESS_H__ */ diff --git a/src/libcamera/include/process_manager.h b/src/libcamera/include/process_manager.h new file mode 100644 index 0000000..9b4bf25 --- /dev/null +++ b/src/libcamera/include/process_manager.h @@ -0,0 +1,40 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +/* + * Copyright (C) 2019, Google Inc. + * + * process_manager.h - Process manager + */ +#ifndef __LIBCAMERA_PROCESS_MANAGER_H__ +#define __LIBCAMERA_PROCESS_MANAGER_H__ + +#include "process.h" + +#include +#include + +namespace libcamera { + +class EventNotifier; + +class ProcessManager +{ +public: + int registerProcess(Process *proc); + + static ProcessManager *instance(); + +private: + std::vector processes_; + + ProcessManager(); + ~ProcessManager(); + void sigchldHandler(int sig); + + int signalfd_; + + EventNotifier *fdEvent_; +}; + +} /* namespace libcamera */ + +#endif /* __LIBCAMERA_PROCESS_MANAGER_H__ */ diff --git a/src/libcamera/meson.build b/src/libcamera/meson.build index 8075b1f..087b578 100644 --- a/src/libcamera/meson.build +++ b/src/libcamera/meson.build @@ -20,6 +20,8 @@ libcamera_sources = files([ 'media_object.cpp', 'object.cpp', 'pipeline_handler.cpp', + 'process.cpp', + 'process_manager.cpp', 'request.cpp', 'signal.cpp', 'stream.cpp', @@ -45,6 +47,8 @@ libcamera_headers = files([ 'include/media_device.h', 'include/media_object.h', 'include/pipeline_handler.h', + 'include/process.h', + 'include/process_manager.h', 'include/utils.h', 'include/v4l2_device.h', 'include/v4l2_subdevice.h', diff --git a/src/libcamera/process.cpp b/src/libcamera/process.cpp new file mode 100644 index 0000000..ea7b58d --- /dev/null +++ b/src/libcamera/process.cpp @@ -0,0 +1,140 @@ +/* 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 "ipa_module.h" +#include "log.h" +#include "process_manager.h" +#include "utils.h" + +/** + * \file process.h + * \brief Process object + * + * TODO add stuff here + */ + +namespace libcamera { + +LOG_DEFINE_CATEGORY(Process) + +namespace { + +void closefrom_except(int from, const std::vector &fds) +{ + std::vector v(fds); + sort(v.begin(), v.end()); + + DIR *dir = opendir("/proc/self/fd"); + if (!dir) + return; + + struct dirent *ent; + while ((ent = readdir(dir)) != nullptr) { + int fd; + if (sscanf(ent->d_name, "%d", &fd) == 1 && fd >= from && + fd != dirfd(dir) && !std::binary_search(v.begin(), v.end(), fd)) + close(fd); + } + + closedir(dir); + return; +} + +} + +/** + * \class Process + * \brief Manager for processes + * + * TODO write this + */ + +Process::Process() + : pid_(-1), execed_(false) +{ +} + +Process::~Process() +{ +} + +/** + * \brief Fork and exec a process, and close fds + * \param[in] path Path to executable + * \param[in] args Arguments to pass to executable + * \param[in] fds Vector of file descriptors to keep open + * + * 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 a positive socket file descriptor on successful fork, exec, and + * closing the file descriptors, or a negative error code otherwise + */ +int Process::exec(const std::string &path, const std::vector &args, const std::vector &fds) +{ + int childPid; + + if (execed_) + return 0; + + if ((childPid = fork()) == -1) { + int err = errno; + LOG(Process, Error) << "Failed to fork: " << strerror(err); + return err; + } else if (childPid) { + std::cout << "parent uid = " << getuid() << std::endl; + pid_ = childPid; + ProcessManager::instance()->registerProcess(this); + + execed_ = true; + + return 0; + } else { + int ret; + if (unshare(CLONE_NEWUSER|CLONE_NEWNET)) { + ret = -errno; + LOG(Process, Error) + << "Failed to isolate IPA: " << strerror(-ret); + exit(ret); + } + + std::cout << "child uid = " << getuid() << std::endl; + + closefrom_except(3, fds); + + const char **argv = new const char *[args.size() + 2]; + int len = args.size(); + argv[0] = path.c_str(); + for (int i = 0; i < len; i++) + argv[i+1] = args[i].c_str(); + argv[len+1] = NULL; + + execv(path.c_str(), (char **)argv); + + ret = -errno; + LOG(Process, Error) << "Failed to exec: " << strerror(-ret); + exit(ret); + } +} + +} /* namespace libcamera */ diff --git a/src/libcamera/process_manager.cpp b/src/libcamera/process_manager.cpp new file mode 100644 index 0000000..1ba0cfb --- /dev/null +++ b/src/libcamera/process_manager.cpp @@ -0,0 +1,104 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +/* + * Copyright (C) 2019, Google Inc. + * + * process_manager.cpp - Process manager + */ + +#include "process_manager.h" + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "ipa_module.h" +#include "log.h" +#include "utils.h" + +/** + * \file process_manager.h + * \brief Process manager + * + * TODO add stuff here + */ + +namespace libcamera { + +LOG_DEFINE_CATEGORY(ProcessManager) + +/** + * \class ProcessManager + * \brief Manager for processes + * + * TODO make this nicer + */ + +void ProcessManager::sigchldHandler(int sig) +{ + /* TODO give the process the status? */ + for (Process *p : processes_) + if ((p->pid_ = waitpid(p->pid_, NULL, WNOHANG))) + p->sigchldHandler(); +} + + +/** + * \brief Register process with process manager + * \param[in] proc Process to register + * + * Add proc to the process manager to manage. + * + * \todo add things to manage + * + * \return zero on success, or negative error value + */ +int ProcessManager::registerProcess(Process *proc) +{ + processes_.push_back(proc); + + return 0; +} + +ProcessManager::ProcessManager() +{ + sigset_t mask; + sigemptyset(&mask); + sigaddset(&mask, SIGCHLD); + + signalfd_ = signalfd(-1, &mask, SFD_NONBLOCK); + fdEvent_ = new EventNotifier(signalfd_, EventNotifier::Read); +} + +ProcessManager::~ProcessManager() +{ + delete fdEvent_; + close(signalfd_); +} + +/** + * \brief Retrieve the Process manager instance + * + * The ProcessManager is a singleton and can't be constructed manually. This + * function 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; +} + +} /* namespace libcamera */