[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