[libcamera-devel,01/23] libcamera: ProcessManager: make ProcessManager lifetime explicitly managed

Message ID 20200915142038.28757-2-paul.elder@ideasonboard.com
State Accepted
Headers show
Series
  • IPA isolation implementation
Related show

Commit Message

Paul Elder Sept. 15, 2020, 2:20 p.m. UTC
If any Process instances are destroyed after the ProcessManager is
destroyed, then a segfault will occur.

Fix this by making the lifetime of the ProcessManager explicit, and make
the CameraManager construct and deconstruct (automatically, via a unique
pointer) the ProcessManager.

Signed-off-by: Paul Elder <paul.elder@ideasonboard.com>
---
 include/libcamera/internal/process.h | 27 ++++++++++++++++
 src/libcamera/camera_manager.cpp     |  2 ++
 src/libcamera/process.cpp            | 46 ++++++++++++----------------
 3 files changed, 48 insertions(+), 27 deletions(-)

Comments

Laurent Pinchart Sept. 16, 2020, 12:01 a.m. UTC | #1
Hi Paul,

Thank you for the patch.

On Tue, Sep 15, 2020 at 11:20:16PM +0900, Paul Elder wrote:
> If any Process instances are destroyed after the ProcessManager is
> destroyed, then a segfault will occur.
> 
> Fix this by making the lifetime of the ProcessManager explicit, and make
> the CameraManager construct and deconstruct (automatically, via a unique
> pointer) the ProcessManager.

I can't see a unique pointer. The code looks fine, only the commit
message seems to need an update.

Reviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>

> Signed-off-by: Paul Elder <paul.elder@ideasonboard.com>
> ---
>  include/libcamera/internal/process.h | 27 ++++++++++++++++
>  src/libcamera/camera_manager.cpp     |  2 ++
>  src/libcamera/process.cpp            | 46 ++++++++++++----------------
>  3 files changed, 48 insertions(+), 27 deletions(-)
> 
> diff --git a/include/libcamera/internal/process.h b/include/libcamera/internal/process.h
> index 36595106..df697c7f 100644
> --- a/include/libcamera/internal/process.h
> +++ b/include/libcamera/internal/process.h
> @@ -7,6 +7,7 @@
>  #ifndef __LIBCAMERA_INTERNAL_PROCESS_H__
>  #define __LIBCAMERA_INTERNAL_PROCESS_H__
>  
> +#include <signal.h>
>  #include <string>
>  #include <vector>
>  
> @@ -50,6 +51,32 @@ private:
>  	friend class ProcessManager;
>  };
>  
> +class ProcessManager
> +{
> +public:
> +	ProcessManager();
> +	~ProcessManager();
> +
> +	void registerProcess(Process *proc);
> +
> +	static ProcessManager *instance();
> +
> +	int writePipe() const;
> +
> +	const struct sigaction &oldsa() const;
> +
> +private:
> +	static ProcessManager *self_;
> +
> +	void sighandler(EventNotifier *notifier);
> +
> +	std::list<Process *> processes_;
> +
> +	struct sigaction oldsa_;
> +	EventNotifier *sigEvent_;
> +	int pipe_[2];
> +};
> +
>  } /* namespace libcamera */
>  
>  #endif /* __LIBCAMERA_INTERNAL_PROCESS_H__ */
> diff --git a/src/libcamera/camera_manager.cpp b/src/libcamera/camera_manager.cpp
> index 47d56256..b8d3ccc8 100644
> --- a/src/libcamera/camera_manager.cpp
> +++ b/src/libcamera/camera_manager.cpp
> @@ -18,6 +18,7 @@
>  #include "libcamera/internal/ipa_manager.h"
>  #include "libcamera/internal/log.h"
>  #include "libcamera/internal/pipeline_handler.h"
> +#include "libcamera/internal/process.h"
>  #include "libcamera/internal/thread.h"
>  #include "libcamera/internal/utils.h"
>  
> @@ -67,6 +68,7 @@ private:
>  	std::unique_ptr<DeviceEnumerator> enumerator_;
>  
>  	IPAManager ipaManager_;
> +	ProcessManager processManager_;
>  };
>  
>  CameraManager::Private::Private(CameraManager *cm)
> diff --git a/src/libcamera/process.cpp b/src/libcamera/process.cpp
> index 994190dc..72b5afe2 100644
> --- a/src/libcamera/process.cpp
> +++ b/src/libcamera/process.cpp
> @@ -41,28 +41,6 @@ LOG_DEFINE_CATEGORY(Process)
>   * 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<Process *> processes_;
> -
> -	struct sigaction oldsa_;
> -	EventNotifier *sigEvent_;
> -	int pipe_[2];
> -};
>  
>  namespace {
>  
> @@ -127,8 +105,20 @@ void ProcessManager::registerProcess(Process *proc)
>  	processes_.push_back(proc);
>  }
>  
> +ProcessManager *ProcessManager::self_ = nullptr;
> +
> +/**
> + * \brief Construct a ProcessManager instance
> + *
> + * The ProcessManager class is meant to only be instantiated once, by the
> + * CameraManager.
> + */
>  ProcessManager::ProcessManager()
>  {
> +	if (self_)
> +		LOG(Process, Fatal)
> +			<< "Multiple ProcessManager objects are not allowed";
> +
>  	sigaction(SIGCHLD, NULL, &oldsa_);
>  
>  	struct sigaction sa;
> @@ -145,6 +135,8 @@ ProcessManager::ProcessManager()
>  			<< "Failed to initialize pipe for signal handling";
>  	sigEvent_ = new EventNotifier(pipe_[0], EventNotifier::Read);
>  	sigEvent_->activated.connect(this, &ProcessManager::sighandler);
> +
> +	self_ = this;
>  }
>  
>  ProcessManager::~ProcessManager()
> @@ -153,21 +145,21 @@ ProcessManager::~ProcessManager()
>  	delete sigEvent_;
>  	close(pipe_[0]);
>  	close(pipe_[1]);
> +
> +	self_ = nullptr;
>  }
>  
>  /**
>   * \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.
> + * The ProcessManager is constructed by the CameraManager. This function shall
> + * be used to retrieve the single instance of the manager.
>   *
>   * \return The Process manager instance
>   */
>  ProcessManager *ProcessManager::instance()
>  {
> -	static ProcessManager processManager;
> -	return &processManager;
> +	return self_;
>  }
>  
>  /**
Niklas Söderlund Sept. 16, 2020, 4:10 p.m. UTC | #2
Hi Paul,

Thanks for your work.

On 2020-09-15 23:20:16 +0900, Paul Elder wrote:
> If any Process instances are destroyed after the ProcessManager is
> destroyed, then a segfault will occur.
> 
> Fix this by making the lifetime of the ProcessManager explicit, and make
> the CameraManager construct and deconstruct (automatically, via a unique
> pointer) the ProcessManager.
> 
> Signed-off-by: Paul Elder <paul.elder@ideasonboard.com>

With the comment about commit message pointed out by Laurent fixed,

Reviewed-by: Niklas Söderlund <niklas.soderlund@ragnatech.se>

> ---
>  include/libcamera/internal/process.h | 27 ++++++++++++++++
>  src/libcamera/camera_manager.cpp     |  2 ++
>  src/libcamera/process.cpp            | 46 ++++++++++++----------------
>  3 files changed, 48 insertions(+), 27 deletions(-)
> 
> diff --git a/include/libcamera/internal/process.h b/include/libcamera/internal/process.h
> index 36595106..df697c7f 100644
> --- a/include/libcamera/internal/process.h
> +++ b/include/libcamera/internal/process.h
> @@ -7,6 +7,7 @@
>  #ifndef __LIBCAMERA_INTERNAL_PROCESS_H__
>  #define __LIBCAMERA_INTERNAL_PROCESS_H__
>  
> +#include <signal.h>
>  #include <string>
>  #include <vector>
>  
> @@ -50,6 +51,32 @@ private:
>  	friend class ProcessManager;
>  };
>  
> +class ProcessManager
> +{
> +public:
> +	ProcessManager();
> +	~ProcessManager();
> +
> +	void registerProcess(Process *proc);
> +
> +	static ProcessManager *instance();
> +
> +	int writePipe() const;
> +
> +	const struct sigaction &oldsa() const;
> +
> +private:
> +	static ProcessManager *self_;
> +
> +	void sighandler(EventNotifier *notifier);
> +
> +	std::list<Process *> processes_;
> +
> +	struct sigaction oldsa_;
> +	EventNotifier *sigEvent_;
> +	int pipe_[2];
> +};
> +
>  } /* namespace libcamera */
>  
>  #endif /* __LIBCAMERA_INTERNAL_PROCESS_H__ */
> diff --git a/src/libcamera/camera_manager.cpp b/src/libcamera/camera_manager.cpp
> index 47d56256..b8d3ccc8 100644
> --- a/src/libcamera/camera_manager.cpp
> +++ b/src/libcamera/camera_manager.cpp
> @@ -18,6 +18,7 @@
>  #include "libcamera/internal/ipa_manager.h"
>  #include "libcamera/internal/log.h"
>  #include "libcamera/internal/pipeline_handler.h"
> +#include "libcamera/internal/process.h"
>  #include "libcamera/internal/thread.h"
>  #include "libcamera/internal/utils.h"
>  
> @@ -67,6 +68,7 @@ private:
>  	std::unique_ptr<DeviceEnumerator> enumerator_;
>  
>  	IPAManager ipaManager_;
> +	ProcessManager processManager_;
>  };
>  
>  CameraManager::Private::Private(CameraManager *cm)
> diff --git a/src/libcamera/process.cpp b/src/libcamera/process.cpp
> index 994190dc..72b5afe2 100644
> --- a/src/libcamera/process.cpp
> +++ b/src/libcamera/process.cpp
> @@ -41,28 +41,6 @@ LOG_DEFINE_CATEGORY(Process)
>   * 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<Process *> processes_;
> -
> -	struct sigaction oldsa_;
> -	EventNotifier *sigEvent_;
> -	int pipe_[2];
> -};
>  
>  namespace {
>  
> @@ -127,8 +105,20 @@ void ProcessManager::registerProcess(Process *proc)
>  	processes_.push_back(proc);
>  }
>  
> +ProcessManager *ProcessManager::self_ = nullptr;
> +
> +/**
> + * \brief Construct a ProcessManager instance
> + *
> + * The ProcessManager class is meant to only be instantiated once, by the
> + * CameraManager.
> + */
>  ProcessManager::ProcessManager()
>  {
> +	if (self_)
> +		LOG(Process, Fatal)
> +			<< "Multiple ProcessManager objects are not allowed";
> +
>  	sigaction(SIGCHLD, NULL, &oldsa_);
>  
>  	struct sigaction sa;
> @@ -145,6 +135,8 @@ ProcessManager::ProcessManager()
>  			<< "Failed to initialize pipe for signal handling";
>  	sigEvent_ = new EventNotifier(pipe_[0], EventNotifier::Read);
>  	sigEvent_->activated.connect(this, &ProcessManager::sighandler);
> +
> +	self_ = this;
>  }
>  
>  ProcessManager::~ProcessManager()
> @@ -153,21 +145,21 @@ ProcessManager::~ProcessManager()
>  	delete sigEvent_;
>  	close(pipe_[0]);
>  	close(pipe_[1]);
> +
> +	self_ = nullptr;
>  }
>  
>  /**
>   * \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.
> + * The ProcessManager is constructed by the CameraManager. This function shall
> + * be used to retrieve the single instance of the manager.
>   *
>   * \return The Process manager instance
>   */
>  ProcessManager *ProcessManager::instance()
>  {
> -	static ProcessManager processManager;
> -	return &processManager;
> +	return self_;
>  }
>  
>  /**
> -- 
> 2.27.0
> 
> _______________________________________________
> libcamera-devel mailing list
> libcamera-devel@lists.libcamera.org
> https://lists.libcamera.org/listinfo/libcamera-devel

Patch

diff --git a/include/libcamera/internal/process.h b/include/libcamera/internal/process.h
index 36595106..df697c7f 100644
--- a/include/libcamera/internal/process.h
+++ b/include/libcamera/internal/process.h
@@ -7,6 +7,7 @@ 
 #ifndef __LIBCAMERA_INTERNAL_PROCESS_H__
 #define __LIBCAMERA_INTERNAL_PROCESS_H__
 
+#include <signal.h>
 #include <string>
 #include <vector>
 
@@ -50,6 +51,32 @@  private:
 	friend class ProcessManager;
 };
 
+class ProcessManager
+{
+public:
+	ProcessManager();
+	~ProcessManager();
+
+	void registerProcess(Process *proc);
+
+	static ProcessManager *instance();
+
+	int writePipe() const;
+
+	const struct sigaction &oldsa() const;
+
+private:
+	static ProcessManager *self_;
+
+	void sighandler(EventNotifier *notifier);
+
+	std::list<Process *> processes_;
+
+	struct sigaction oldsa_;
+	EventNotifier *sigEvent_;
+	int pipe_[2];
+};
+
 } /* namespace libcamera */
 
 #endif /* __LIBCAMERA_INTERNAL_PROCESS_H__ */
diff --git a/src/libcamera/camera_manager.cpp b/src/libcamera/camera_manager.cpp
index 47d56256..b8d3ccc8 100644
--- a/src/libcamera/camera_manager.cpp
+++ b/src/libcamera/camera_manager.cpp
@@ -18,6 +18,7 @@ 
 #include "libcamera/internal/ipa_manager.h"
 #include "libcamera/internal/log.h"
 #include "libcamera/internal/pipeline_handler.h"
+#include "libcamera/internal/process.h"
 #include "libcamera/internal/thread.h"
 #include "libcamera/internal/utils.h"
 
@@ -67,6 +68,7 @@  private:
 	std::unique_ptr<DeviceEnumerator> enumerator_;
 
 	IPAManager ipaManager_;
+	ProcessManager processManager_;
 };
 
 CameraManager::Private::Private(CameraManager *cm)
diff --git a/src/libcamera/process.cpp b/src/libcamera/process.cpp
index 994190dc..72b5afe2 100644
--- a/src/libcamera/process.cpp
+++ b/src/libcamera/process.cpp
@@ -41,28 +41,6 @@  LOG_DEFINE_CATEGORY(Process)
  * 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<Process *> processes_;
-
-	struct sigaction oldsa_;
-	EventNotifier *sigEvent_;
-	int pipe_[2];
-};
 
 namespace {
 
@@ -127,8 +105,20 @@  void ProcessManager::registerProcess(Process *proc)
 	processes_.push_back(proc);
 }
 
+ProcessManager *ProcessManager::self_ = nullptr;
+
+/**
+ * \brief Construct a ProcessManager instance
+ *
+ * The ProcessManager class is meant to only be instantiated once, by the
+ * CameraManager.
+ */
 ProcessManager::ProcessManager()
 {
+	if (self_)
+		LOG(Process, Fatal)
+			<< "Multiple ProcessManager objects are not allowed";
+
 	sigaction(SIGCHLD, NULL, &oldsa_);
 
 	struct sigaction sa;
@@ -145,6 +135,8 @@  ProcessManager::ProcessManager()
 			<< "Failed to initialize pipe for signal handling";
 	sigEvent_ = new EventNotifier(pipe_[0], EventNotifier::Read);
 	sigEvent_->activated.connect(this, &ProcessManager::sighandler);
+
+	self_ = this;
 }
 
 ProcessManager::~ProcessManager()
@@ -153,21 +145,21 @@  ProcessManager::~ProcessManager()
 	delete sigEvent_;
 	close(pipe_[0]);
 	close(pipe_[1]);
+
+	self_ = nullptr;
 }
 
 /**
  * \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.
+ * The ProcessManager is constructed by the CameraManager. This function shall
+ * be used to retrieve the single instance of the manager.
  *
  * \return The Process manager instance
  */
 ProcessManager *ProcessManager::instance()
 {
-	static ProcessManager processManager;
-	return &processManager;
+	return self_;
 }
 
 /**