[libcamera-devel] [RFC PATCH v2 2/7] libcamera: process, process manager: create process and manager classes
Paul Elder
paul.elder at ideasonboard.com
Wed Jul 3 10:00:02 CEST 2019
Add a Process class to abstract a process, and a ProcessManager singleton
to monitor and manage the processes.
Signed-off-by: Paul Elder <paul.elder at ideasonboard.com>
---
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 <string>
+#include <vector>
+
+namespace libcamera {
+
+class Process
+{
+public:
+ Process();
+ virtual ~Process();
+
+ int exec(const std::string &path, const std::vector<std::string> &args, const std::vector<int> &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 <string>
+#include <vector>
+
+namespace libcamera {
+
+class EventNotifier;
+
+class ProcessManager
+{
+public:
+ int registerProcess(Process *proc);
+
+ static ProcessManager *instance();
+
+private:
+ std::vector<Process *> 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 <algorithm>
+#include <iostream>
+#include <vector>
+
+#include <dirent.h>
+#include <string.h>
+#include <sys/socket.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#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<int> &fds)
+{
+ std::vector<int> 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<std::string> &args, const std::vector<int> &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 <algorithm>
+#include <iostream>
+#include <vector>
+
+#include <dirent.h>
+#include <signal.h>
+#include <string.h>
+#include <sys/signalfd.h>
+#include <sys/socket.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <unistd.h>
+
+#include <libcamera/event_notifier.h>
+
+#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 */
--
2.20.1
More information about the libcamera-devel
mailing list