[libcamera-devel,v2,1/9] libcamera: Add Semaphore class

Message ID 20191028104913.14985-2-laurent.pinchart@ideasonboard.com
State Accepted
Headers show
Series
  • Add support for blocking method invocation
Related show

Commit Message

Laurent Pinchart Oct. 28, 2019, 10:49 a.m. UTC
Add a general-purpose counting semaphore class.

Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
---
 src/libcamera/include/meson.build |   1 +
 src/libcamera/include/semaphore.h |  34 ++++++++++
 src/libcamera/meson.build         |   1 +
 src/libcamera/semaphore.cpp       | 103 ++++++++++++++++++++++++++++++
 4 files changed, 139 insertions(+)
 create mode 100644 src/libcamera/include/semaphore.h
 create mode 100644 src/libcamera/semaphore.cpp

Comments

Niklas Söderlund Oct. 28, 2019, 11:06 a.m. UTC | #1
Hi Laurent,

Thanks for your patch.

On 2019-10-28 12:49:05 +0200, Laurent Pinchart wrote:
> Add a general-purpose counting semaphore class.
> 
> Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>

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

> ---
>  src/libcamera/include/meson.build |   1 +
>  src/libcamera/include/semaphore.h |  34 ++++++++++
>  src/libcamera/meson.build         |   1 +
>  src/libcamera/semaphore.cpp       | 103 ++++++++++++++++++++++++++++++
>  4 files changed, 139 insertions(+)
>  create mode 100644 src/libcamera/include/semaphore.h
>  create mode 100644 src/libcamera/semaphore.cpp
> 
> diff --git a/src/libcamera/include/meson.build b/src/libcamera/include/meson.build
> index 2c74d29bd925..64c2155f90cf 100644
> --- a/src/libcamera/include/meson.build
> +++ b/src/libcamera/include/meson.build
> @@ -17,6 +17,7 @@ libcamera_headers = files([
>      'message.h',
>      'pipeline_handler.h',
>      'process.h',
> +    'semaphore.h',
>      'thread.h',
>      'utils.h',
>      'v4l2_controls.h',
> diff --git a/src/libcamera/include/semaphore.h b/src/libcamera/include/semaphore.h
> new file mode 100644
> index 000000000000..c6b286536eb3
> --- /dev/null
> +++ b/src/libcamera/include/semaphore.h
> @@ -0,0 +1,34 @@
> +/* SPDX-License-Identifier: LGPL-2.1-or-later */
> +/*
> + * Copyright (C) 2019, Google Inc.
> + *
> + * semaphore.h - General-purpose counting semaphore
> + */
> +#ifndef __LIBCAMERA_SEMAPHORE_H__
> +#define __LIBCAMERA_SEMAPHORE_H__
> +
> +#include <condition_variable>
> +
> +#include "thread.h"
> +
> +namespace libcamera {
> +
> +class Semaphore
> +{
> +public:
> +	Semaphore(unsigned int n = 0);
> +
> +	unsigned int available();
> +	void acquire(unsigned int n = 1);
> +	bool tryAcquire(unsigned int n = 1);
> +	void release(unsigned int n = 1);
> +
> +private:
> +	Mutex mutex_;
> +	std::condition_variable cv_;
> +	unsigned int available_;
> +};
> +
> +} /* namespace libcamera */
> +
> +#endif /* __LIBCAMERA_SEMAPHORE_H__ */
> diff --git a/src/libcamera/meson.build b/src/libcamera/meson.build
> index d329820b9582..dab5dbff77b7 100644
> --- a/src/libcamera/meson.build
> +++ b/src/libcamera/meson.build
> @@ -27,6 +27,7 @@ libcamera_sources = files([
>      'pipeline_handler.cpp',
>      'process.cpp',
>      'request.cpp',
> +    'semaphore.cpp',
>      'signal.cpp',
>      'stream.cpp',
>      'thread.cpp',
> diff --git a/src/libcamera/semaphore.cpp b/src/libcamera/semaphore.cpp
> new file mode 100644
> index 000000000000..ce1eae4914ed
> --- /dev/null
> +++ b/src/libcamera/semaphore.cpp
> @@ -0,0 +1,103 @@
> +/* SPDX-License-Identifier: LGPL-2.1-or-later */
> +/*
> + * Copyright (C) 2019, Google Inc.
> + *
> + * semaphore.cpp - General-purpose counting semaphore
> + */
> +
> +#include "semaphore.h"
> +#include "thread.h"
> +
> +/**
> + * \file semaphore.h
> + * \brief General-purpose counting semaphore
> + */
> +
> +namespace libcamera {
> +
> +/**
> + * \class Semaphore
> + * \brief General-purpose counting semaphore
> + *
> + * A semaphore is a locking primitive that protects resources. It is created
> + * with an initial number of resources (which may be 0), and offers two
> + * primitives to acquire and release resources. The acquire() method tries to
> + * acquire a number of resources, and blocks if not enough resources are
> + * available until they get released. The release() method releases a number of
> + * resources, waking up any consumer blocked on an acquire() call.
> + */
> +
> +/**
> + * \brief Construct a semaphore with \a n resources
> + * \param[in] n The resource count
> + */
> +Semaphore::Semaphore(unsigned int n)
> +	: available_(n)
> +{
> +}
> +
> +/**
> + * \brief Retrieve the number of available resources
> + * \return The number of available resources
> + */
> +unsigned int Semaphore::available()
> +{
> +	MutexLocker locker(mutex_);
> +	return available_;
> +}
> +
> +/**
> + * \brief Acquire \a n resources
> + * \param[in] n The resource count
> + *
> + * This method attempts to acquire \a n resources. If \a n is higher than the
> + * number of available resources, the call will block until enough resources
> + * become available.
> + */
> +void Semaphore::acquire(unsigned int n)
> +{
> +	MutexLocker locker(mutex_);
> +	cv_.wait(locker, [&] { return available_ >= n; });
> +	available_ -= n;
> +}
> +
> +/**
> + * \brief Try to acquire \a n resources without blocking
> + * \param[in] n The resource count
> + *
> + * This method attempts to acquire \a n resources. If \a n is higher than the
> + * number of available resources, it returns false immediately without
> + * acquiring any resource. Otherwise it acquires the resources and returns
> + * true.
> + *
> + * \return True if the resources have been acquired, false otherwise
> + */
> +bool Semaphore::tryAcquire(unsigned int n)
> +{
> +	MutexLocker locker(mutex_);
> +	if (available_ < n)
> +		return false;
> +
> +	available_ -= n;
> +	return true;
> +}
> +
> +/**
> + * \brief Release \a n resources
> + * \param[in] n The resource count
> + *
> + * This method releases \a n resources, increasing the available resource count
> + * by \a n. If the number of available resources becomes large enough for any
> + * consumer blocked on an acquire() call, those consumers get woken up.
> + */
> +void Semaphore::release(unsigned int n)
> +{
> +	{
> +		MutexLocker locker(mutex_);
> +		available_ += n;
> +	}
> +
> +	cv_.notify_all();
> +}
> +
> +} /* namespace libcamera */
> -- 
> Regards,
> 
> Laurent Pinchart
> 
> _______________________________________________
> libcamera-devel mailing list
> libcamera-devel@lists.libcamera.org
> https://lists.libcamera.org/listinfo/libcamera-devel

Patch

diff --git a/src/libcamera/include/meson.build b/src/libcamera/include/meson.build
index 2c74d29bd925..64c2155f90cf 100644
--- a/src/libcamera/include/meson.build
+++ b/src/libcamera/include/meson.build
@@ -17,6 +17,7 @@  libcamera_headers = files([
     'message.h',
     'pipeline_handler.h',
     'process.h',
+    'semaphore.h',
     'thread.h',
     'utils.h',
     'v4l2_controls.h',
diff --git a/src/libcamera/include/semaphore.h b/src/libcamera/include/semaphore.h
new file mode 100644
index 000000000000..c6b286536eb3
--- /dev/null
+++ b/src/libcamera/include/semaphore.h
@@ -0,0 +1,34 @@ 
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+/*
+ * Copyright (C) 2019, Google Inc.
+ *
+ * semaphore.h - General-purpose counting semaphore
+ */
+#ifndef __LIBCAMERA_SEMAPHORE_H__
+#define __LIBCAMERA_SEMAPHORE_H__
+
+#include <condition_variable>
+
+#include "thread.h"
+
+namespace libcamera {
+
+class Semaphore
+{
+public:
+	Semaphore(unsigned int n = 0);
+
+	unsigned int available();
+	void acquire(unsigned int n = 1);
+	bool tryAcquire(unsigned int n = 1);
+	void release(unsigned int n = 1);
+
+private:
+	Mutex mutex_;
+	std::condition_variable cv_;
+	unsigned int available_;
+};
+
+} /* namespace libcamera */
+
+#endif /* __LIBCAMERA_SEMAPHORE_H__ */
diff --git a/src/libcamera/meson.build b/src/libcamera/meson.build
index d329820b9582..dab5dbff77b7 100644
--- a/src/libcamera/meson.build
+++ b/src/libcamera/meson.build
@@ -27,6 +27,7 @@  libcamera_sources = files([
     'pipeline_handler.cpp',
     'process.cpp',
     'request.cpp',
+    'semaphore.cpp',
     'signal.cpp',
     'stream.cpp',
     'thread.cpp',
diff --git a/src/libcamera/semaphore.cpp b/src/libcamera/semaphore.cpp
new file mode 100644
index 000000000000..ce1eae4914ed
--- /dev/null
+++ b/src/libcamera/semaphore.cpp
@@ -0,0 +1,103 @@ 
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+/*
+ * Copyright (C) 2019, Google Inc.
+ *
+ * semaphore.cpp - General-purpose counting semaphore
+ */
+
+#include "semaphore.h"
+#include "thread.h"
+
+/**
+ * \file semaphore.h
+ * \brief General-purpose counting semaphore
+ */
+
+namespace libcamera {
+
+/**
+ * \class Semaphore
+ * \brief General-purpose counting semaphore
+ *
+ * A semaphore is a locking primitive that protects resources. It is created
+ * with an initial number of resources (which may be 0), and offers two
+ * primitives to acquire and release resources. The acquire() method tries to
+ * acquire a number of resources, and blocks if not enough resources are
+ * available until they get released. The release() method releases a number of
+ * resources, waking up any consumer blocked on an acquire() call.
+ */
+
+/**
+ * \brief Construct a semaphore with \a n resources
+ * \param[in] n The resource count
+ */
+Semaphore::Semaphore(unsigned int n)
+	: available_(n)
+{
+}
+
+/**
+ * \brief Retrieve the number of available resources
+ * \return The number of available resources
+ */
+unsigned int Semaphore::available()
+{
+	MutexLocker locker(mutex_);
+	return available_;
+}
+
+/**
+ * \brief Acquire \a n resources
+ * \param[in] n The resource count
+ *
+ * This method attempts to acquire \a n resources. If \a n is higher than the
+ * number of available resources, the call will block until enough resources
+ * become available.
+ */
+void Semaphore::acquire(unsigned int n)
+{
+	MutexLocker locker(mutex_);
+	cv_.wait(locker, [&] { return available_ >= n; });
+	available_ -= n;
+}
+
+/**
+ * \brief Try to acquire \a n resources without blocking
+ * \param[in] n The resource count
+ *
+ * This method attempts to acquire \a n resources. If \a n is higher than the
+ * number of available resources, it returns false immediately without
+ * acquiring any resource. Otherwise it acquires the resources and returns
+ * true.
+ *
+ * \return True if the resources have been acquired, false otherwise
+ */
+bool Semaphore::tryAcquire(unsigned int n)
+{
+	MutexLocker locker(mutex_);
+	if (available_ < n)
+		return false;
+
+	available_ -= n;
+	return true;
+}
+
+/**
+ * \brief Release \a n resources
+ * \param[in] n The resource count
+ *
+ * This method releases \a n resources, increasing the available resource count
+ * by \a n. If the number of available resources becomes large enough for any
+ * consumer blocked on an acquire() call, those consumers get woken up.
+ */
+void Semaphore::release(unsigned int n)
+{
+	{
+		MutexLocker locker(mutex_);
+		available_ += n;
+	}
+
+	cv_.notify_all();
+}
+
+} /* namespace libcamera */