[libcamera-devel] [PATCH v2 06/11] libcamera: Add event notification infrastructure

Jacopo Mondi jacopo at jmondi.org
Tue Jan 8 10:43:43 CET 2019


Hi Laurent,
   a few minor things on comments, otherwise

Reviewed-by: Jacopo Mondi <jacopo at jmondi.org>

On Tue, Jan 08, 2019 at 01:11:46AM +0200, Laurent Pinchart wrote:
> Add three new classes, EventDispatcher, EventNotifier and Timer, that
> define APIs for file descriptor event notification and timers. The
> implementation of the EventDispatcher is meant to be provided to
> libcamera by the application.
>
> The event dispatcher is integrated twith the camera manager to implement
> automatic registration of timers and events.
>
> Signed-off-by: Laurent Pinchart <laurent.pinchart at ideasonboard.com>
> Reviewed-by: Niklas Söderlund <niklas.soderlund at ragnatech.se>
> ---
> Changes since v1:
>
> - Rename EventNotifier::isEnabled() to EventNotifier::enabled()
> - Fix typo in documentation
> ---
>  include/libcamera/camera_manager.h   |   7 ++
>  include/libcamera/event_dispatcher.h |  33 ++++++++
>  include/libcamera/event_notifier.h   |  42 ++++++++++
>  include/libcamera/libcamera.h        |   1 +
>  include/libcamera/meson.build        |   3 +
>  include/libcamera/timer.h            |  37 ++++++++
>  src/libcamera/camera_manager.cpp     |  42 +++++++++-
>  src/libcamera/event_dispatcher.cpp   | 103 +++++++++++++++++++++++
>  src/libcamera/event_notifier.cpp     | 121 +++++++++++++++++++++++++++
>  src/libcamera/meson.build            |   3 +
>  src/libcamera/timer.cpp              | 105 +++++++++++++++++++++++
>  11 files changed, 496 insertions(+), 1 deletion(-)
>  create mode 100644 include/libcamera/event_dispatcher.h
>  create mode 100644 include/libcamera/event_notifier.h
>  create mode 100644 include/libcamera/timer.h
>  create mode 100644 src/libcamera/event_dispatcher.cpp
>  create mode 100644 src/libcamera/event_notifier.cpp
>  create mode 100644 src/libcamera/timer.cpp
>
> diff --git a/include/libcamera/camera_manager.h b/include/libcamera/camera_manager.h
> index e14da0f893b3..15e7c162032a 100644
> --- a/include/libcamera/camera_manager.h
> +++ b/include/libcamera/camera_manager.h
> @@ -14,6 +14,7 @@ namespace libcamera {
>
>  class Camera;
>  class DeviceEnumerator;
> +class EventDispatcher;
>  class PipelineHandler;
>
>  class CameraManager
> @@ -27,13 +28,19 @@ public:
>
>  	static CameraManager *instance();
>
> +	void setEventDispatcher(EventDispatcher *dispatcher);
> +	EventDispatcher *eventDispatcher();
> +
>  private:
>  	CameraManager();
>  	CameraManager(const CameraManager &) = delete;
>  	void operator=(const CameraManager &) = delete;
> +	~CameraManager();
>
>  	DeviceEnumerator *enumerator_;
>  	std::vector<PipelineHandler *> pipes_;
> +
> +	EventDispatcher *dispatcher_;
>  };
>
>  } /* namespace libcamera */
> diff --git a/include/libcamera/event_dispatcher.h b/include/libcamera/event_dispatcher.h
> new file mode 100644
> index 000000000000..c20518c6866d
> --- /dev/null
> +++ b/include/libcamera/event_dispatcher.h
> @@ -0,0 +1,33 @@
> +/* SPDX-License-Identifier: LGPL-2.1-or-later */
> +/*
> + * Copyright (C) 2019, Google Inc.
> + *
> + * event_dispatcher.h - Event dispatcher
> + */
> +#ifndef __LIBCAMERA_EVENT_DISPATCHER_H__
> +#define __LIBCAMERA_EVENT_DISPATCHER_H__
> +
> +#include <vector>
> +
> +namespace libcamera {
> +
> +class EventNotifier;
> +class Timer;
> +
> +class EventDispatcher
> +{
> +public:
> +	virtual ~EventDispatcher();
> +
> +	virtual void registerEventNotifier(EventNotifier *notifier) = 0;
> +	virtual void unregisterEventNotifier(EventNotifier *notifier) = 0;
> +
> +	virtual void registerTimer(Timer *timer) = 0;
> +	virtual void unregisterTimer(Timer *timer) = 0;
> +
> +	virtual void processEvents() = 0;
> +};
> +
> +} /* namespace libcamera */
> +
> +#endif /* __LIBCAMERA_EVENT_DISPATCHER_H__ */
> diff --git a/include/libcamera/event_notifier.h b/include/libcamera/event_notifier.h
> new file mode 100644
> index 000000000000..1e9b6da1340c
> --- /dev/null
> +++ b/include/libcamera/event_notifier.h
> @@ -0,0 +1,42 @@
> +/* SPDX-License-Identifier: LGPL-2.1-or-later */
> +/*
> + * Copyright (C) 2019, Google Inc.
> + *
> + * event_notifier.h - File descriptor event notifier
> + */
> +#ifndef __LIBCAMERA_EVENT_NOTIFIER_H__
> +#define __LIBCAMERA_EVENT_NOTIFIER_H__
> +
> +#include <libcamera/signal.h>
> +
> +namespace libcamera {
> +
> +class EventNotifier
> +{
> +public:
> +	enum Type {
> +		Read,
> +		Write,
> +		Exception,
> +	};
> +
> +	EventNotifier(int fd, Type type);
> +	virtual ~EventNotifier();
> +
> +	Type type() const { return type_; }
> +	int fd() const { return fd_; }
> +
> +	bool enabled() const { return enabled_; }
> +	void setEnabled(bool enable);
> +
> +	Signal<EventNotifier *> activated;
> +
> +private:
> +	int fd_;
> +	Type type_;
> +	bool enabled_;
> +};
> +
> +} /* namespace libcamera */
> +
> +#endif /* __LIBCAMERA_EVENT_NOTIFIER_H__ */
> diff --git a/include/libcamera/libcamera.h b/include/libcamera/libcamera.h
> index f9556a8bce62..785babefa1c8 100644
> --- a/include/libcamera/libcamera.h
> +++ b/include/libcamera/libcamera.h
> @@ -9,5 +9,6 @@
>
>  #include <libcamera/camera.h>
>  #include <libcamera/camera_manager.h>
> +#include <libcamera/event_dispatcher.h>
>
>  #endif /* __LIBCAMERA_LIBCAMERA_H__ */
> diff --git a/include/libcamera/meson.build b/include/libcamera/meson.build
> index 6f87689ea528..d7cb55ba4a49 100644
> --- a/include/libcamera/meson.build
> +++ b/include/libcamera/meson.build
> @@ -1,8 +1,11 @@
>  libcamera_api = files([
>      'camera.h',
>      'camera_manager.h',
> +    'event_dispatcher.h',
> +    'event_notifier.h',
>      'libcamera.h',
>      'signal.h',
> +    'timer.h',
>  ])
>
>  install_headers(libcamera_api,
> diff --git a/include/libcamera/timer.h b/include/libcamera/timer.h
> new file mode 100644
> index 000000000000..97dcc01f493d
> --- /dev/null
> +++ b/include/libcamera/timer.h
> @@ -0,0 +1,37 @@
> +/* SPDX-License-Identifier: LGPL-2.1-or-later */
> +/*
> + * Copyright (C) 2019, Google Inc.
> + *
> + * timer.h - Generic timer
> + */
> +#ifndef __LIBCAMERA_TIMER_H__
> +#define __LIBCAMERA_TIMER_H__
> +
> +#include <cstdint>
> +
> +#include <libcamera/signal.h>
> +
> +namespace libcamera {
> +
> +class Timer
> +{
> +public:
> +	Timer();
> +
> +	void start(unsigned int msec);
> +	void stop();
> +	bool isRunning() const;
> +
> +	unsigned int interval() const { return interval_; }
> +	uint64_t deadline() const { return deadline_; }
> +
> +	Signal<Timer *> timeout;
> +
> +private:
> +	unsigned int interval_;
> +	uint64_t deadline_;
> +};
> +
> +} /* namespace libcamera */
> +
> +#endif /* __LIBCAMERA_TIMER_H__ */
> diff --git a/src/libcamera/camera_manager.cpp b/src/libcamera/camera_manager.cpp
> index 1a9d2f38e3b9..cbfd977f1e3c 100644
> --- a/src/libcamera/camera_manager.cpp
> +++ b/src/libcamera/camera_manager.cpp
> @@ -6,8 +6,10 @@
>   */
>
>  #include <libcamera/camera_manager.h>
> +#include <libcamera/event_dispatcher.h>
>
>  #include "device_enumerator.h"
> +#include "log.h"
>  #include "pipeline_handler.h"
>
>  /**
> @@ -37,10 +39,15 @@
>  namespace libcamera {
>
>  CameraManager::CameraManager()
> -	: enumerator_(nullptr)
> +	: enumerator_(nullptr), dispatcher_(nullptr)
>  {
>  }
>
> +CameraManager::~CameraManager()
> +{
> +	delete dispatcher_;
> +}
> +
>  /**
>   * \brief Start the camera manager
>   *
> @@ -176,4 +183,37 @@ CameraManager *CameraManager::instance()
>  	return &manager;
>  }
>
> +/**
> + * \brief Set the event dispatcher
> + * \param dispatcher Pointer to the event dispatcher
> + *
> + * libcamera requires an event dispatcher to integrate event notification and
> + * timers with the application event loop. Applications shall call this function
> + * once and only once before the camera manager is started with start() to set
> + * the event dispatcher.
> + *
> + * The CameraManager takes ownership of the event dispatcher and will delete it
> + * when the application terminates.
> + */
> +void CameraManager::setEventDispatcher(EventDispatcher *dispatcher)
> +{
> +	if (dispatcher_) {
> +		LOG(Warning) << "Event dispatcher is already set";
> +		return;
> +	}
> +
> +	dispatcher_ = dispatcher;
> +}
> +
> +/**
> + * \fn CameraManager::eventDispatcher()

Not needed, as the comment applies to the function just after the
comment block.

> + * \brief Retrieve the event dispatcher
> + * \return Pointer to the event dispatcher, or nullptr if no event dispatcher
> + * has been set
> + */
> +EventDispatcher *CameraManager::eventDispatcher()
> +{
> +	return dispatcher_;
> +}
> +
>  } /* namespace libcamera */
> diff --git a/src/libcamera/event_dispatcher.cpp b/src/libcamera/event_dispatcher.cpp
> new file mode 100644
> index 000000000000..b893ab046985
> --- /dev/null
> +++ b/src/libcamera/event_dispatcher.cpp
> @@ -0,0 +1,103 @@
> +/* SPDX-License-Identifier: LGPL-2.1-or-later */
> +/*
> + * Copyright (C) 2019, Google Inc.
> + *
> + * event_dispatcher.cpp - Event dispatcher
> + */
> +
> +#include <libcamera/event_dispatcher.h>
> +
> +/**
> + * \file event_dispatcher.h
> + */
> +
> +namespace libcamera {
> +
> +/**
> + * \class EventDispatcher
> + * \brief Interface to manage the libcamera events and timers
> + *
> + * The EventDispatcher class allows the integration of the application event
> + * loop with libcamera by abstracting how events and timers are managed and
> + * processed.
> + *
> + * To listen to events, libcamera creates EventNotifier instances and register

s/register/registers ?

> + * them with the dispatcher with registerEventNotifier(). The event notifier
> + * \ref EventNotifier::activated signal is then emitted by the dispatcher
> + * whenever the event is detected.
> + *
> + * To set timers, libcamera creates Timer instances and register them with the

s/register/registers ?

> + * dispatcher with registerTimer(). The timer \ref Timer::timeout signal is then
> + * emitted by the dispatcher when the timer times out.
> + */
> +
> +EventDispatcher::~EventDispatcher()
> +{
> +}
> +
> +/**
> + * \fn EventDispatcher::registerEventNotifier()
> + * \brief Register an event notifier
> + * \param notifier The event notifier to register
> + *
> + * Once the \a notifier is registered with the dispatcher, the dispatcher will
> + * emit the notifier \ref EventNotifier::activated signal whenever a
> + * corresponding event is detected on the notifier's file descriptor. The event
> + * is monitored until the notifier is unregistered with
> + * unregisterEventNotifier().
> + *
> + * Registering multiple notifiers for the same file descriptor and event type is
> + * not allowed and results in undefined behaviour.
> + */
> +
> +/**
> + * \fn EventDispatcher::unregisterEventNotifier()
> + * \brief Unregister an event notifier
> + * \param notifier The event notifier to unregister
> + *
> + * After this function returns the \a notifier is guaranteed not to emit the
> + * \ref EventNotifier::activated signal.
> + *
> + * If the notifier isn't registered, this function performs no operation.
> + */
> +
> +/**
> + * \fn EventDispatcher::registerTimer()
> + * \brief Register a timer
> + * \param timer The timer to register
> + *
> + * Once the \a timer is registered with the dispatcher, the dispatcher will emit
> + * the timer \ref Timer::timeout signal when the timer times out. The timer can
> + * be unregistered with unregisterTimer() before it times out, in which case the
> + * signal will not be emitted.
> + *
> + * When the \a timer times out, it is automatically unregistered by the
> + * dispatcher and can be registered back as early as from the \ref Timer::timeout
> + * signal handlers.
> + *
> + * Registering the same timer multiple times is not allowed and results in
> + * undefined behaviour.
> + */
> +
> +/**
> + * \fn EventDispatcher::unregisterTimer()
> + * \brief Unregister a timer
> + * \param timer The timer to unregister
> + *
> + * After this function returns the \a timer is guaranteed not to emit the
> + * \ref Timer::timeout signal.
> + *
> + * If the timer isn't registered, this function performs no operation.
> + */
> +
> +/**
> + * \fn EventDispatcher::processEvents()
> + * \brief Wait for and process pending events
> + *
> + * This function processes all pending events associated with registered event
> + * notifiers and timers and signals the corresponding EventNotifier and Timer
> + * objects. If no events are pending, it waits for the first event and processes
> + * it before returning.
> + */
> +
> +} /* namespace libcamera */
> diff --git a/src/libcamera/event_notifier.cpp b/src/libcamera/event_notifier.cpp
> new file mode 100644
> index 000000000000..8dc45a546a11
> --- /dev/null
> +++ b/src/libcamera/event_notifier.cpp
> @@ -0,0 +1,121 @@
> +/* SPDX-License-Identifier: LGPL-2.1-or-later */
> +/*
> + * Copyright (C) 2019, Google Inc.
> + *
> + * event_notifier.cpp - File descriptor event notifier
> + */
> +
> +#include <libcamera/camera_manager.h>
> +#include <libcamera/event_dispatcher.h>
> +#include <libcamera/event_notifier.h>
> +
> +/**
> + * \file event_notifier.h
> + * \brief Event notifier

Event notifier for file descriptor events ?

> + */
> +
> +namespace libcamera {
> +
> +/**
> + * \class EventNotifier
> + * \brief Notify of activity on a file descriptor
> + *
> + * The EventNotifier models a file descriptor event source that can be
> + * monitored. It is created with the file descriptor to be monitored and the
> + * type of event, and is enabled by default. It will emit the \ref activated
> + * signal whenever an event of the monitored type occurs on the file descriptor.
> + *
> + * Supported type of events are EventNotifier::Read, EventNotifier::Write and
> + * EventNotifier::Exception. The type is specified when constructing the
> + * notifier, and can be retrieved using the type() function. To listen to
> + * multiple event types on the same file descriptor multiple notifiers must be
> + * created.
> + *
> + * The notifier can be disabled with the setEnable() function. When the notifier
> + * is disabled it ignores events and does not emit the \ref activated signal.
> + * The notifier can then be re-enabled with the setEnable() function.
> + *
> + * Creating multiple notifiers of the same type for the same file descriptor is
> + * not allowed and results in undefined behaviour.
> + *
> + * Notifier events are detected and dispatched from the
> + * EventDispatcher::processEvents() function.
> + */
> +
> +/**
> + * \enum EventNotifier::Type
> + * Type of file descriptor event to listen for.
> + * \var EventNotifier::Read
> + * Data is available to be read from the file descriptor
> + * \var EventNotifier::Write
> + * Data can be written to the file descriptor
> + * \var EventNotifier::Exception
> + * An exception has occurred on the file descriptor
> + */
> +
> +/**
> + * \brief Construct an event notifier with a file descriptor and event type
> + * \param fd The file descriptor to monitor
> + * \param type The event type to monitor
> + */
> +EventNotifier::EventNotifier(int fd, Type type)
> +	: fd_(fd), type_(type), enabled_(false)
> +{
> +	setEnabled(true);
> +}
> +
> +EventNotifier::~EventNotifier()
> +{
> +	setEnabled(false);
> +}
> +
> +/**
> + * \fn EventNotifier::type()
> + * \brief Retrive the type of the event being monitored
> + * \return The type of the event
> + */
> +
> +/**
> + * \fn EventNotifier::fd()
> + * \brief Retrive the file descriptor being monitored
> + * \return The file descriptor
> + */
> +
> +/**
> + * \fn EventNotifier::enabled()
> + * \brief Retrieve the notifier state
> + * \return true if the notifier is enabled, or false otherwise

s/true/True ?

> + * \sa setEnable()
> + */
> +
> +/**
> + * \brief Enable or disable the notifier
> + * \param enable true to enable the notifier, false to disable it

s/true/True ?

> + *
> + * This function enables or disables the notifier. A disabled notifier ignores
> + * events and does not emit the \ref activated signal.
> + */
> +void EventNotifier::setEnabled(bool enable)
> +{
> +	if (enabled_ == enable)
> +		return;
> +
> +	enabled_ = enable;
> +
> +	EventDispatcher *dispatcher = CameraManager::instance()->eventDispatcher();
> +	if (enable)
> +		dispatcher->registerEventNotifier(this);
> +	else
> +		dispatcher->unregisterEventNotifier(this);
> +}
> +
> +/**
> + * \var EventNotifier::activated
> + * \brief Signal emitted when the event occurs
> + *
> + * This signal is emitted when the event \ref type() occurs on the file
> + * descriptor monitored by the notifier. The notifier pointer is passed as a
> + * parameter.
> + */
> +
> +} /* namespace libcamera */
> diff --git a/src/libcamera/meson.build b/src/libcamera/meson.build
> index 3ec86e75b57e..61fb93205b34 100644
> --- a/src/libcamera/meson.build
> +++ b/src/libcamera/meson.build
> @@ -2,11 +2,14 @@ libcamera_sources = files([
>      'camera.cpp',
>      'camera_manager.cpp',
>      'device_enumerator.cpp',
> +    'event_dispatcher.cpp',
> +    'event_notifier.cpp',
>      'log.cpp',
>      'media_device.cpp',
>      'media_object.cpp',
>      'pipeline_handler.cpp',
>      'signal.cpp',
> +    'timer.cpp',
>  ])
>
>  libcamera_headers = files([
> diff --git a/src/libcamera/timer.cpp b/src/libcamera/timer.cpp
> new file mode 100644
> index 000000000000..57c49aa2ef36
> --- /dev/null
> +++ b/src/libcamera/timer.cpp
> @@ -0,0 +1,105 @@
> +/* SPDX-License-Identifier: LGPL-2.1-or-later */
> +/*
> + * Copyright (C) 2019, Google Inc.
> + *
> + * timer.cpp - Generic timer
> + */
> +
> +#include <time.h>
> +
> +#include <libcamera/camera_manager.h>
> +#include <libcamera/event_dispatcher.h>
> +#include <libcamera/timer.h>
> +
> +#include "log.h"
> +
> +/**
> + * \file timer.h
> + * \brief Generic timer
> + */
> +
> +namespace libcamera {
> +
> +/**
> + * \class Timer
> + * \brief Single-shot timer interface
> + *
> + * The Timer class models a single-shot timer that is started with start() and
> + * emits the \ref timeout signal when it times out.
> + *
> + * Once started the timer will run until it times out. It can be stopped with
> + * stop(), and once it times out or is stopped, can be started again with
> + * start().
> + */
> +
> +/**
> + * \brief Construct a timer
> + */
> +Timer::Timer()
> +{
> +}
> +
> +/**
> + * \brief Start or restart the timer with a timeout of \a msec
> + * \param msec The timer duration in milliseconds
> + *
> + * If the timer is already running it will be stopped and restarted.
> + */
> +void Timer::start(unsigned int msec)
> +{
> +	struct timespec tp;
> +	clock_gettime(CLOCK_MONOTONIC, &tp);
> +
> +	interval_ = msec;
> +	deadline_ = tp.tv_sec * 1000000000ULL + tp.tv_nsec + msec * 1000000;
> +
> +	LOG(Debug) << "Starting timer " << this << " with interval " << msec
> +		   << ": deadline " << deadline_;
> +
> +	CameraManager::instance()->eventDispatcher()->registerTimer(this);
> +}
> +
> +/**
> + * \brief Stop the timer
> + *
> + * After this function returns the timer is guaranteed not to emit the
> + * \ref timeout signal.
> + *
> + * If the timer is not running this function performs no operation.
> + */
> +void Timer::stop()
> +{
> +	CameraManager::instance()->eventDispatcher()->unregisterTimer(this);
> +
> +	deadline_ = 0;
> +}
> +
> +/**
> + * \brief

Empty brief. I know, there's not much to say on this function...

> + * \return true if the timer is running, false otherwise

s/true/True ?

> + */
> +bool Timer::isRunning() const
> +{
> +	return deadline_ != 0;
> +}
> +
> +/**
> + * \fn Timer::interval()
> + * \brief Retrieve the timer interval
> + * \return The timer interval in milliseconds
> + */
> +
> +/**
> + * \fn Timer::deadline()
> + * \brief Retrieve the timer deadline
> + * \return The timer deadline in nanoseconds
> + */
> +
> +/**
> + * \var Timer::timeout
> + * \brief Signal emitted when the timer times out
> + *
> + * The timer pointer is passed as a parameter.
> + */
> +
> +} /* namespace libcamera */

Thanks
  j

> --
> Regards,
>
> Laurent Pinchart
>
> _______________________________________________
> libcamera-devel mailing list
> libcamera-devel at lists.libcamera.org
> https://lists.libcamera.org/listinfo/libcamera-devel
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 833 bytes
Desc: not available
URL: <https://lists.libcamera.org/pipermail/libcamera-devel/attachments/20190108/38f165cb/attachment-0001.sig>


More information about the libcamera-devel mailing list